aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/components/ReviewCard/ReviewCard.tsx43
-rw-r--r--src/components/UploadImage/UploadImage.tsx30
-rw-r--r--src/pages/HomePage/HomePage.tsx73
-rw-r--r--src/pages/HomePage/ReviewForm.tsx74
-rw-r--r--src/pages/NotificationsPage/NotificationsPage.tsx2
5 files changed, 206 insertions, 16 deletions
diff --git a/src/components/ReviewCard/ReviewCard.tsx b/src/components/ReviewCard/ReviewCard.tsx
new file mode 100644
index 0000000..97581fc
--- /dev/null
+++ b/src/components/ReviewCard/ReviewCard.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import {
+ Card,
+ CardContent,
+ Typography,
+ Divider
+} from '@material-ui/core/';
+import { Rating } from '@material-ui/lab';
+import { Feedback } from 'which-types';
+
+import UserStrip from '../UserStrip/UserStrip';
+
+interface PropTypes {
+ feedback: Feedback;
+}
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ margin: theme.spacing(4, 0, 1, 0)
+ }
+}));
+
+const ReviewCard: React.FC<PropTypes> = ({ feedback }) => {
+ const classes = useStyles();
+
+ return (
+ <Card className={classes.root} elevation={2}>
+ <UserStrip
+ user={feedback.author}
+ info={<Rating value={feedback.score} readOnly size="small" />}
+ />
+ <Divider />
+ <CardContent>
+ <Typography>
+ {feedback.contents}
+ </Typography>
+ </CardContent>
+ </Card>
+ );
+};
+
+export default ReviewCard;
diff --git a/src/components/UploadImage/UploadImage.tsx b/src/components/UploadImage/UploadImage.tsx
index 8ad65d5..836b2a0 100644
--- a/src/components/UploadImage/UploadImage.tsx
+++ b/src/components/UploadImage/UploadImage.tsx
@@ -1,11 +1,15 @@
import React, { useState } from 'react';
-import Button from '@material-ui/core/Button';
-import TextField from '@material-ui/core/TextField';
-import Dialog from '@material-ui/core/Dialog';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogContentText from '@material-ui/core/DialogContentText';
-import DialogTitle from '@material-ui/core/DialogTitle';
+import {
+ Button,
+ TextField,
+ Dialog,
+ DialogActions,
+ DialogContent,
+ DialogContentText,
+ DialogTitle,
+ FormControlLabel,
+ Switch
+} from '@material-ui/core';
interface PropTypes {
isOpen: boolean;
@@ -15,6 +19,7 @@ interface PropTypes {
const UploadImage: React.FC<PropTypes> = ({ setIsOpen, isOpen, callback }) => {
const [url, setUrl] = useState<string>('');
+ const [isInstagramLink, setIsInstagramLink] = useState<boolean>(false);
const handleClose = () => {
@@ -22,14 +27,19 @@ const UploadImage: React.FC<PropTypes> = ({ setIsOpen, isOpen, callback }) => {
};
const handleSubmit = () => {
+ const result = isInstagramLink ? `${url.slice(0, url.length - 29)}/media/?size=l` : url;
+ callback(result || '');
handleClose();
- callback(url || '');
};
const handleChange = (event:React.ChangeEvent<HTMLInputElement>) => {
setUrl(event.target.value);
};
+ const handleSwitch = () => {
+ setIsInstagramLink(!isInstagramLink);
+ };
+
return (
<div>
<Dialog open={isOpen} onClose={handleClose}>
@@ -48,6 +58,10 @@ const UploadImage: React.FC<PropTypes> = ({ setIsOpen, isOpen, callback }) => {
autoComplete="off"
onChange={handleChange}
/>
+ <FormControlLabel
+ control={<Switch color="primary" onClick={handleSwitch} checked={isInstagramLink} size="small" />}
+ label="It's an Instagram link"
+ />
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
diff --git a/src/pages/HomePage/HomePage.tsx b/src/pages/HomePage/HomePage.tsx
index f00289a..5a33b42 100644
--- a/src/pages/HomePage/HomePage.tsx
+++ b/src/pages/HomePage/HomePage.tsx
@@ -4,9 +4,10 @@ import {
Divider,
Grid,
Button,
- Link
+ Link,
+ useMediaQuery
} from '@material-ui/core/';
-import { makeStyles } from '@material-ui/core/styles';
+import { makeStyles, useTheme } from '@material-ui/core/styles';
import TrendingUpIcon from '@material-ui/icons/TrendingUp';
import { Rating } from '@material-ui/lab';
import { Feedback } from 'which-types';
@@ -14,6 +15,8 @@ import { Feedback } from 'which-types';
import { useNavigate } from '../../hooks/useNavigate';
import { useAuth } from '../../hooks/useAuth';
import { get } from '../../requests';
+import ReviewCard from '../../components/ReviewCard/ReviewCard';
+import ReviewForm from './ReviewForm';
const useStyles = makeStyles(theme => ({
root: {
@@ -29,6 +32,11 @@ const useStyles = makeStyles(theme => ({
},
signup: {
marginLeft: theme.spacing(2)
+ },
+ reviews: {
+ [theme.breakpoints.up('md')]: {
+ padding: theme.spacing(0, 10)
+ }
}
}));
@@ -36,7 +44,9 @@ const HomePage: React.FC = () => {
const [feedbacks, setFeedbacks] = useState<Feedback[]>([]);
const classes = useStyles();
const { navigate } = useNavigate();
- const { isAuthenticated } = useAuth();
+ const { isAuthenticated, user } = useAuth();
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const rating = feedbacks.length && feedbacks.reduce(
(acc: number, feedback: Feedback) => acc + feedback.score,
@@ -62,6 +72,40 @@ const HomePage: React.FC = () => {
const ReactLink = <Link href="https://reactjs.org/">React</Link>;
const FeathersLink = <Link href="https://feathersjs.com">Feathers</Link>;
const MUILink = <Link href="https://material-ui.com">Material-UI</Link>;
+ const EmailLink = <Link href="mailto: eug-vs@keemail.me">eug-vs@keemail.me</Link>;
+
+ const Reviews = (
+ <div className={classes.reviews}>
+ {feedbacks.map(feedback => <ReviewCard feedback={feedback} />)}
+ </div>
+ );
+
+ const FeedbackSection = feedbacks.findIndex((feedback: Feedback) => feedback.author._id === user?._id) >= 0 ? (
+ <p>
+ You have already left feedback for this version.
+ If you have more to say, please open GitHub issue or contact us directly via email: {EmailLink}.
+ Alternatively, you can just wait for another application patch to come out.
+ </p>
+ ) : (
+ <>
+ <p>
+ Here you can share your thougts about Which with us!
+ Note that you can ony leave feedback once per application version (there will be plenty of them later).
+ </p>
+ {isAuthenticated() ? <ReviewForm /> : (
+ <>
+ <p> You must be authorized to leave feedback.</p>
+ <Button
+ variant="outlined"
+ color="primary"
+ onClick={handleSignUp}
+ >
+ sign in
+ </Button>
+ </>
+ )}
+ </>
+ );
return (
<div className={classes.root}>
@@ -72,14 +116,17 @@ const HomePage: React.FC = () => {
<img src={`${process.env.PUBLIC_URL}/which-logo-512.png`} alt="logo" className={classes.logo} />
</Grid>
<Grid item>
- <Rating value={rating} readOnly size="large" />
+ {rating && <Rating value={rating} readOnly size="large" />}
</Grid>
<Grid item>
- <Typography variant="h5" className={classes.score}>
- User score: {rating.toFixed(1)}
- </Typography>
+ {rating && (
+ <Typography variant="h5" className={classes.score}>
+ User score: {rating.toFixed(1)}
+ </Typography>
+ )}
</Grid>
</Grid>
+ {isMobile || Reviews}
</Grid>
<Grid item xs={12} md={5}>
<Grid container direction="column" spacing={6}>
@@ -133,6 +180,18 @@ const HomePage: React.FC = () => {
</Button>
</Typography>
</Grid>
+ <Grid item>
+ <Typography variant="h4"> Leave feedback </Typography>
+ <Divider />
+ <Typography>
+ {FeedbackSection}
+ </Typography>
+ </Grid>
+ {isMobile && (
+ <Grid item>
+ {Reviews}
+ </Grid>
+ )}
</Grid>
</Grid>
</Grid>
diff --git a/src/pages/HomePage/ReviewForm.tsx b/src/pages/HomePage/ReviewForm.tsx
new file mode 100644
index 0000000..7ad0880
--- /dev/null
+++ b/src/pages/HomePage/ReviewForm.tsx
@@ -0,0 +1,74 @@
+import React, { useState } from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import { TextField, Button } from '@material-ui/core';
+import { Rating } from '@material-ui/lab';
+import { useSnackbar } from 'notistack';
+
+import { post } from '../../requests';
+import { useNavigate } from '../../hooks/useNavigate';
+
+const version = 'v1.0.0';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ display: 'flex',
+ flexDirection: 'column'
+ },
+ textField: {
+ margin: theme.spacing(2, 0)
+ }
+}));
+
+const ReviewForm: React.FC = () => {
+ const [contents, setContents] = useState<string>('');
+ const [score, setScore] = useState<number>(0);
+ const classes = useStyles();
+ const { navigate } = useNavigate();
+ const { enqueueSnackbar } = useSnackbar();
+
+ const handleSubmit = (): void => {
+ if (contents && score) {
+ post('/feedback', { contents, score, version }).then(() => {
+ enqueueSnackbar('Your feedback has been submitted!', {
+ variant: 'success'
+ });
+ navigate('feed');
+ });
+ }
+ };
+
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
+ setContents(event.target?.value || '');
+ };
+
+ const handleChangeRating = (event: React.ChangeEvent<Record<string, unknown>>, newScore: number | null): void => {
+ setScore(newScore || 0);
+ };
+
+ return (
+ <div className={classes.root}>
+ <Rating value={score} onChange={handleChangeRating} size="large" />
+ <TextField
+ value={contents}
+ onChange={handleChange}
+ label="Feedback"
+ variant="outlined"
+ className={classes.textField}
+ rows={4}
+ multiline
+ />
+ <div>
+ <Button
+ variant="contained"
+ color="primary"
+ size="large"
+ onClick={handleSubmit}
+ >
+ submit
+ </Button>
+ </div>
+ </div>
+ );
+};
+
+export default ReviewForm;
diff --git a/src/pages/NotificationsPage/NotificationsPage.tsx b/src/pages/NotificationsPage/NotificationsPage.tsx
index 3c39ba3..064fbd4 100644
--- a/src/pages/NotificationsPage/NotificationsPage.tsx
+++ b/src/pages/NotificationsPage/NotificationsPage.tsx
@@ -4,7 +4,7 @@ import { Typography } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
- marginTop: theme.spacing(40),
+ marginTop: theme.spacing(25),
textAlign: 'center'
}
}));