fixed vite related issues, leftover issues from Moving to MUI, some visual changes

This commit is contained in:
QkoSad
2024-09-24 22:43:21 +03:00
parent d9455d002b
commit be03889ff3
22 changed files with 355 additions and 283 deletions
+1
View File
@@ -1,2 +1,3 @@
node_modules node_modules
App.css App.css
start_in_tmux.sh
+1 -2
View File
@@ -121,7 +121,6 @@ export const addPost =
(formData: { text: string }): AppThunk => (formData: { text: string }): AppThunk =>
async (dispatch) => { async (dispatch) => {
try { try {
console.log(1);
const res = await api.post("/posts", formData); const res = await api.post("/posts", formData);
dispatch(addPostAction(res.data)); dispatch(addPostAction(res.data));
@@ -170,7 +169,6 @@ export const getPost =
} }
} }
}; };
// Add comment
export const addComment = export const addComment =
(postId: string, formData: { text: string }): AppThunk => (postId: string, formData: { text: string }): AppThunk =>
async (dispatch) => { async (dispatch) => {
@@ -181,6 +179,7 @@ export const addComment =
dispatch(createAlert("Comment Added", "success")); dispatch(createAlert("Comment Added", "success"));
} catch (err: unknown) { } catch (err: unknown) {
console.log(err);
if (err instanceof AxiosError) { if (err instanceof AxiosError) {
if ( if (
err !== undefined && err !== undefined &&
+1
View File
@@ -96,6 +96,7 @@ export const createProfile =
try { try {
const res = await api.post("/profile", formData); const res = await api.post("/profile", formData);
console.log(res);
dispatch(getProfile(res.data)); dispatch(getProfile(res.data));
dispatch( dispatch(
+53 -28
View File
@@ -3,27 +3,46 @@ import { deleteEducation } from "../../actions/profile";
import formatDate from "../../utils/formatDate"; import formatDate from "../../utils/formatDate";
import { EducationType } from "../../types"; import { EducationType } from "../../types";
import { useAppDispatch } from "../../utils/hooks"; import { useAppDispatch } from "../../utils/hooks";
import { Box, Typography } from "@mui/material"; import {
Box,
Button,
TableRow,
Table,
TableBody,
TableCell,
TableHead,
Typography,
TableContainer,
} from "@mui/material";
const Education = ({ education }: { education: EducationType[] }) => { const Education = ({ education }: { education: EducationType[] }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
if (!education) return <></>; if (!education) return <></>;
const educations = education.map((edu) => ( const educations = education.map((edu) => (
<tr key={edu._id}> <TableRow key={edu._id}>
<td>{edu.school}</td> <TableCell
<td className="hide-sm">{edu.degree}</td> // style={{
<td> // wordWrap: "break-word",
{formatDate(edu.from)} - {edu.to ? formatDate(edu.to) : "Now"} // }}
</td>
<td>
<button
onClick={async () => await dispatch(deleteEducation(edu._id))}
className="btn btn-danger"
> >
{edu.school}
</TableCell>
<TableCell
// style={{ wordWrap: "break-word" }}
>
{edu.degree}
</TableCell>
<TableCell
// style={{ wordWrap: "break-word" }}
>
{formatDate(edu.from)} - {edu.to ? formatDate(edu.to) : "Now"}
</TableCell>
<TableCell>
<Button onClick={async () => await dispatch(deleteEducation(edu._id))}>
Delete Delete
</button> </Button>
</td> </TableCell>
</tr> </TableRow>
)); ));
if (education.length === 0) if (education.length === 0)
@@ -35,20 +54,26 @@ const Education = ({ education }: { education: EducationType[] }) => {
</Box> </Box>
); );
return ( return (
<> <Box>
<Typography variant="h5">Education Credentials</Typography> <Typography variant="h2">Education Credentials</Typography>
<table className="table"> <Table
<thead> // style={{
<tr> // tableLayout: "fixed",
<th>School</th> // width: "50%",
<th className="hide-sm">Degree</th> // alignSelf: "left",
<th className="hide-sm">Years</th> // }}
<th /> >
</tr> <TableHead>
</thead> <TableRow>
<tbody>{educations}</tbody> <TableCell>School</TableCell>
</table> <TableCell>Degree</TableCell>
</> <TableCell>Years</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>{educations}</TableBody>
</Table>
</Box>
); );
}; };
+37 -28
View File
@@ -1,29 +1,36 @@
import { Typography } from "@mui/material";
import React from "react"; import React from "react";
import { deleteExperience } from "../../actions/profile"; import { deleteExperience } from "../../actions/profile";
import { ExperienceType } from "../../types"; import { ExperienceType } from "../../types";
import formatDate from "../../utils/formatDate"; import formatDate from "../../utils/formatDate";
import { useAppDispatch } from "../../utils/hooks"; import { useAppDispatch } from "../../utils/hooks";
import {
Box,
Button,
TableRow,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
Typography,
} from "@mui/material";
const Experience = ({ experience }: { experience: ExperienceType[] }) => { const Experience = ({ experience }: { experience: ExperienceType[] }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
if (!experience) return <></>; if (!experience) return <></>;
const experiences = experience.map((exp) => ( const experiences = experience.map((exp) => (
<tr key={exp._id}> <TableRow key={exp._id}>
<td>{exp.company}</td> <TableCell>{exp.company}</TableCell>
<td className="hide-sm">{exp.title}</td> <TableCell>{exp.title}</TableCell>
<td> <TableCell>
{formatDate(exp.from)} - {exp.to ? formatDate(exp.to) : "Now"} {formatDate(exp.from)} - {exp.to ? formatDate(exp.to) : "Now"}
</td> </TableCell>
<td> <TableCell>
<button <Button onClick={async () => dispatch(deleteExperience(exp._id))}>
onClick={async () => dispatch(deleteExperience(exp._id))}
className="btn btn-danger"
>
Delete Delete
</button> </Button>
</td> </TableCell>
</tr> </TableRow>
)); ));
if (experiences.length === 0) if (experiences.length === 0)
@@ -34,20 +41,22 @@ const Experience = ({ experience }: { experience: ExperienceType[] }) => {
); );
return ( return (
<> <Box>
<h2 className="my-2">Experience Credentials</h2> <Typography variant="h2">Experience Credentials</Typography>
<table className="table"> <TableContainer>
<thead> <Table>
<tr> <TableHead>
<th>Company</th> <TableRow>
<th className="hide-sm">Title</th> <TableCell>Company</TableCell>
<th className="hide-sm">Years</th> <TableCell>Title</TableCell>
<th /> <TableCell>Years</TableCell>
</tr> <TableCell />
</thead> </TableRow>
<tbody>{experiences}</tbody> </TableHead>
</table> <TableBody>{experiences}</TableBody>
</> </Table>
</TableContainer>
</Box>
); );
}; };
+14 -7
View File
@@ -1,15 +1,22 @@
import React from "react"; import { Box } from "@mui/material";
import AlertMUI from "@mui/material/Alert";
import { useAppSelector } from "../../utils/hooks"; import { useAppSelector } from "../../utils/hooks";
const Alert = () => { const Alert = () => {
const alerts = useAppSelector((state) => state.alert); const alerts = useAppSelector((state) => state.alert);
return ( return (
<div className="alert-wrapper"> <Box sx={{ position: "fixed" }}>
{alerts.map((alert) => ( {alerts.map((alert) =>
<div key={alert.id} className={`alert alert-${alert.alertType}`}> alert.alertType === "danger" ? (
<AlertMUI key={alert.id} severity="error">
{alert.msg} {alert.msg}
</div> </AlertMUI>
))} ) : (
</div> <AlertMUI key={alert.id} severity="success">
{alert.msg}
</AlertMUI>
),
)}
</Box>
); );
}; };
+3 -3
View File
@@ -16,9 +16,9 @@ const CommentForm = ({ postId }: { postId: string }) => {
flexDirection="column" flexDirection="column"
alignItems="left" alignItems="left"
gap="1rem" gap="1rem"
onSubmit={async (e) => { onSubmit={(e) => {
e.preventDefault(); e.preventDefault();
await dispatch(addComment(postId, { text })); dispatch(addComment(postId, { text }));
setText(""); setText("");
}} }}
> >
@@ -31,7 +31,7 @@ const CommentForm = ({ postId }: { postId: string }) => {
value={text} value={text}
onChange={(e) => setText(e.target.value)} onChange={(e) => setText(e.target.value)}
/> />
<Button>Submit</Button> <Button type="submit">Submit</Button>
</Box> </Box>
</Container> </Container>
); );
+4 -8
View File
@@ -34,18 +34,14 @@ const CommentItem = ({
title={<Link to={`/profile/${user}`}>{name}</Link>} title={<Link to={`/profile/${user}`}>{name}</Link>}
subheader={formatDate(date)} subheader={formatDate(date)}
/> />
<CardContent>
<Typography variant="subtitle1">{text}</Typography>
</CardContent>
<Box display={"inline"}>
{!auth.loading && auth.user !== null && user === auth.user._id && ( {!auth.loading && auth.user !== null && user === auth.user._id && (
<Button <Button onClick={() => dispatch(deleteComment(postId, _id))}>
onClick={async () => await dispatch(deleteComment(postId, _id))}
>
<DeleteIcon /> <DeleteIcon />
</Button> </Button>
)} )}
</Box> <CardContent>
<Typography variant="subtitle1">{text}</Typography>
</CardContent>
</Card> </Card>
</Container> </Container>
); );
+8 -6
View File
@@ -6,8 +6,9 @@ import { useAppDispatch } from "../../utils/hooks";
const PostForm = () => { const PostForm = () => {
const [text, setText] = useState(""); const [text, setText] = useState("");
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const handleSumbit = {};
return ( return (
<Box> <Container>
<Typography>Say Something...</Typography> <Typography>Say Something...</Typography>
<Box <Box
component="form" component="form"
@@ -15,10 +16,9 @@ const PostForm = () => {
gap="1rem" gap="1rem"
noValidate noValidate
sx={{ mt: 3, mb: 3 }} sx={{ mt: 3, mb: 3 }}
onSubmit={async (e) => { onSubmit={(e) => {
console.log(1);
e.preventDefault(); e.preventDefault();
await dispatch(addPost({ text })); dispatch(addPost({ text }));
setText(""); setText("");
}} }}
> >
@@ -32,9 +32,11 @@ const PostForm = () => {
rows={3} rows={3}
required required
/> />
<Button variant="contained">Submit</Button> <Button type="submit" variant="contained">
</Box> Submit
</Button>
</Box> </Box>
</Container>
); );
}; };
+19 -4
View File
@@ -6,13 +6,14 @@ import { Post } from "../../types";
import { useAppDispatch, useAppSelector } from "../../utils/hooks"; import { useAppDispatch, useAppSelector } from "../../utils/hooks";
import { import {
Avatar, Avatar,
Box,
Button, Button,
Card, Card,
CardContent, CardContent,
CardHeader, CardHeader,
CardMedia,
Container, Container,
Table,
TableCell,
TableRow,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import ThumbDownIcon from "@mui/icons-material/ThumbDown"; import ThumbDownIcon from "@mui/icons-material/ThumbDown";
@@ -38,28 +39,42 @@ const PostItem = ({
<Typography variant="subtitle1">{text}</Typography> <Typography variant="subtitle1">{text}</Typography>
</CardContent> </CardContent>
</Card> </Card>
<Box> <Table>
<TableRow>
<TableCell>
<Button onClick={async () => await dispatch(addLike(_id))}> <Button onClick={async () => await dispatch(addLike(_id))}>
<ThumbUpIcon /> <ThumbUpIcon />
</Button> </Button>
</TableCell>
<TableCell>
<Typography display="inline-flex" variant="button"> <Typography display="inline-flex" variant="button">
{likes.length} {likes.length}
</Typography> </Typography>
</TableCell>
<TableCell>
<Button onClick={async () => await dispatch(removeLike(_id))}> <Button onClick={async () => await dispatch(removeLike(_id))}>
<ThumbDownIcon /> <ThumbDownIcon />
</Button> </Button>
</TableCell>
<TableCell>
<Button component={Link} to={`/posts/${_id}`}> <Button component={Link} to={`/posts/${_id}`}>
<Typography>Comments </Typography> <Typography>Comments </Typography>
</Button> </Button>
</TableCell>
<TableCell>
<Typography display="inline-flex" variant="button"> <Typography display="inline-flex" variant="button">
{comments.length} {comments.length}
</Typography> </Typography>
</TableCell>
<TableCell>
{!auth.loading && auth.user !== null && user === auth.user._id && ( {!auth.loading && auth.user !== null && user === auth.user._id && (
<Button onClick={async () => await dispatch(deletePost(_id))}> <Button onClick={async () => await dispatch(deletePost(_id))}>
<DeleteIcon /> <DeleteIcon />
</Button> </Button>
)} )}
</Box> </TableCell>
</TableRow>
</Table>
</Container> </Container>
); );
}; };
@@ -49,7 +49,7 @@ const AddEducation = () => {
formData; formData;
const onChange = ( const onChange = (
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,
) => setFormData({ ...formData, [event.target.name]: event.target.value }); ) => setFormData({ ...formData, [event.target.name]: event.target.value });
return ( return (
@@ -71,7 +71,7 @@ const AddEducation = () => {
onSubmit={async (e) => { onSubmit={async (e) => {
e.preventDefault(); e.preventDefault();
await dispatch(addEducation(formData)).then(() => await dispatch(addEducation(formData)).then(() =>
navigate("/dashboard") navigate("/dashboard"),
); );
}} }}
> >
@@ -79,34 +79,52 @@ const AddEducation = () => {
name="school" name="school"
label="School or Bootcamp" label="School or Bootcamp"
fullWidth fullWidth
value={school}
onChange={onChange}
autoFocus autoFocus
/> />
<TextField name="degree" label="Gegree or Certificate" fullWidth /> <TextField
<TextField name="fieldofstudy" label="Field of Study" fullWidth /> value={degree}
onChange={onChange}
name="degree"
label="Gegree or Certificate"
fullWidth
/>
<TextField
value={fieldofstudy}
onChange={onChange}
name="fieldofstudy"
label="Field of Study"
fullWidth
/>
<Typography variant="body1">From Date</Typography> <Typography variant="body1">From Date</Typography>
<StyledInput type="date" name="from" value={from} onChange={onChange} /> <StyledInput type="date" name="from" value={from} onChange={onChange} />
<Typography> {/* <Typography> */}
<FormControlLabel {/* <FormControlLabel */}
control={ {/* control={ */}
<Checkbox {/* <Checkbox */}
checked={current} {/* checked={current} */}
onChange={() => setFormData({ ...formData, current: !current })} {/* onChange={() => setFormData({ ...formData, current: !current })} */}
inputProps={{ "aria-label": "controlled" }} {/* inputProps={{ "aria-label": "controlled" }} */}
/> {/* /> */}
} {/* } */}
label="Current" {/* label="Current" */}
/> {/* /> */}
</Typography> {/* </Typography> */}
<Typography>To Date</Typography> <Typography>To Date</Typography>
<StyledInput type="date" name="from" value={to} onChange={onChange} /> <StyledInput type="date" name="to" value={to} onChange={onChange} />
<TextField <TextField
name="desc" name="description"
value={description}
onChange={onChange}
label="Program description" label="Program description"
multiline multiline
rows={4} rows={4}
fullWidth fullWidth
/> />
<Button variant="contained">Sumbit Query</Button> <Button variant="contained" type="submit">
Submit Changes
</Button>
</Box> </Box>
<Button component={Link} to="/dashboard"> <Button component={Link} to="/dashboard">
Go Back Go Back
@@ -48,7 +48,7 @@ const AddExperience = () => {
} }
`; `;
const onChange = ( const onChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => setFormData({ ...formData, [e.target.name]: e.target.value }); ) => setFormData({ ...formData, [e.target.name]: e.target.value });
return ( return (
@@ -70,37 +70,59 @@ const AddExperience = () => {
onSubmit={async (e) => { onSubmit={async (e) => {
e.preventDefault(); e.preventDefault();
await dispatch(addExperience(formData)).then(() => await dispatch(addExperience(formData)).then(() =>
navigate("/dashboard") navigate("/dashboard"),
); );
}} }}
> >
<TextField name="title" label="Job Title" fullWidth required /> <TextField
<TextField name="company" label="Company" required /> name="title"
<TextField name="location" label="Location" /> value={title}
label="Job Title"
onChange={onChange}
fullWidth
required
/>
<TextField
onChange={onChange}
value={company}
name="company"
label="Company"
required
/>
<TextField
onChange={onChange}
value={location}
name="location"
label="Location"
/>
<Typography variant="body1">From Date</Typography> <Typography variant="body1">From Date</Typography>
<StyledInput type="date" name="from" value={from} onChange={onChange} /> <StyledInput type="date" name="from" value={from} onChange={onChange} />
<Typography> {/* <Typography> */}
<FormControlLabel {/* <FormControlLabel */}
control={ {/* control={ */}
<Checkbox {/* <Checkbox */}
checked={current} {/* checked={current} */}
onChange={() => setFormData({ ...formData, current: !current })} {/* onChange={() => setFormData({ ...formData, current: !current })} */}
inputProps={{ "aria-label": "controlled" }} {/* inputProps={{ "aria-label": "controlled" }} */}
/> {/* /> */}
} {/* } */}
label="Current" {/* label="Current" */}
/> {/* /> */}
</Typography> {/* </Typography> */}
<Typography>To Date</Typography> <Typography>To Date</Typography>
<StyledInput type="date" name="from" value={to} onChange={onChange} /> <StyledInput type="date" name="to" value={to} onChange={onChange} />
<TextField <TextField
name="desc" name="description"
label="Job description" label="Job description"
multiline multiline
rows={4} rows={4}
fullWidth fullWidth
value={description}
onChange={onChange}
/> />
<Button variant="contained">Sumbit Query</Button> <Button variant="contained" type="submit">
Submit Changes
</Button>
</Box> </Box>
<Button component={Link} to="/dashboard"> <Button component={Link} to="/dashboard">
Go Back Go Back
@@ -86,7 +86,6 @@ const ProfileForm = () => {
const linkedin = data.get("linkedin") as string; const linkedin = data.get("linkedin") as string;
const instagram = data.get("instagram") as string; const instagram = data.get("instagram") as string;
const status = data.get("status") as string; const status = data.get("status") as string;
console.log(data);
await dispatch( await dispatch(
createProfile( createProfile(
{ {
@@ -105,13 +104,14 @@ const ProfileForm = () => {
}, },
editing, editing,
), ),
).then(() => { ).then((res) => {
console.log(res);
if (!editing) navigate("/dashboard"); if (!editing) navigate("/dashboard");
}); });
}; };
return ( return (
<Container maxWidth='md'> <Container maxWidth="md">
<Typography component="h1" variant="h4"> <Typography component="h1" variant="h4">
{creatingProfile ? "Create Your Profile" : "Edit Your Profile"} {creatingProfile ? "Create Your Profile" : "Edit Your Profile"}
</Typography> </Typography>
@@ -128,7 +128,7 @@ const ProfileForm = () => {
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<Typography paddingY="1rem"> <Typography paddingY="1rem">
Could be your own company or onee you work for Could be your own company or one you work for
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
@@ -152,7 +152,7 @@ const ProfileForm = () => {
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<Typography> <Typography>
Please use comma separeted values(eg. HTML, CSS, JavaScript, PHP) Please use comma separeted values (eg. HTML, CSS, JavaScript, PHP)
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
@@ -160,8 +160,8 @@ const ProfileForm = () => {
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<Typography> <Typography>
If you want your latest reepos add a Github link, include your If you want your latest repositories, add a Github link and
username include your username
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
@@ -237,7 +237,7 @@ const ProfileForm = () => {
) : null} ) : null}
<Grid item xs={8}> <Grid item xs={8}>
<Button variant="contained" type="submit"> <Button variant="contained" type="submit">
Sumbit query Submit Changes
</Button> </Button>
</Grid> </Grid>
<Grid item xs={2}> <Grid item xs={2}>
+2 -2
View File
@@ -37,11 +37,11 @@ const Profile = () => {
auth.loading === false && auth.loading === false &&
auth.user !== null && auth.user !== null &&
auth.user._id === profile.user._id && ( auth.user._id === profile.user._id && (
<Button component={Link} to="/edit-profilee"> <Button component={Link} to="/edit-profile">
Edit Profile Edit Profile
</Button> </Button>
)} )}
<Paper elevation={9} sx={{width:'90%'}}> <Paper elevation={9} sx={{ width: "90%" }}>
<ProfileTop profile={profile} /> <ProfileTop profile={profile} />
<ProfileAbout profile={profile} /> <ProfileAbout profile={profile} />
<Box> <Box>
@@ -21,7 +21,7 @@ const ProfileAbout = ({
<Typography>Skill Set</Typography> <Typography>Skill Set</Typography>
<Box> <Box>
{skills.map((skill, index) => ( {skills.map((skill, index) => (
<Box> <Box key={index}>
<Typography>{skill}</Typography> <Typography>{skill}</Typography>
</Box> </Box>
))} ))}
+13 -8
View File
@@ -1,4 +1,11 @@
import { Box, Button, Paper, Typography } from "@mui/material"; import {
Box,
Button,
List,
ListItemText,
Paper,
Typography,
} from "@mui/material";
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { ProfileType } from "../../types"; import { ProfileType } from "../../types";
@@ -15,8 +22,8 @@ const ProfileItem = ({
profile: ProfileType; profile: ProfileType;
}) => { }) => {
return ( return (
<Paper> <Paper sx={{ padding: "100px" }}>
<img src={avatar} alt="" className="round-img" /> <img src={avatar} alt="" />
<Box> <Box>
<Typography>{name}</Typography> <Typography>{name}</Typography>
<Typography> <Typography>
@@ -27,13 +34,11 @@ const ProfileItem = ({
View Profile View Profile
</Button> </Button>
</Box> </Box>
<ul> <List>
{skills.slice(0, 4).map((skill, index) => ( {skills.slice(0, 4).map((skill, index) => (
<li key={index} className="text-primary"> <ListItemText key={index}>{skill}</ListItemText>
<i className="fas fa-check" /> {skill}
</li>
))} ))}
</ul> </List>
</Paper> </Paper>
); );
}; };
+1 -1
View File
@@ -27,7 +27,7 @@ const Profiles = () => {
<Typography variant="h6"> <Typography variant="h6">
Browse and connect with developers Browse and connect with developers
</Typography> </Typography>
<Box> <Box display="flex" flexDirection="row">
{profiles.length > 0 && Array.isArray(profiles) ? ( {profiles.length > 0 && Array.isArray(profiles) ? (
profiles.map((profile) => ( profiles.map((profile) => (
<ProfileItem key={profile._id} profile={profile} /> <ProfileItem key={profile._id} profile={profile} />
-5
View File
@@ -1,5 +0,0 @@
const MONGO_URL = process.env.MONGO_URL || undefined;
module.exports = {
MONGO_URL,
};
+6 -8
View File
@@ -1,20 +1,18 @@
import mongoose from "mongoose"; import mongoose from "mongoose";
// import config from "config"; import config from "config";
const { MONGO_URL } = require("./config");
// const db = config.get('mongoURI'); const db = process.env.MONGO_URL
? process.env.MONGO_URL
: config.get("mongoURI");
const connectDB = async () => { const connectDB = async () => {
try { try {
if (typeof MONGO_URL === "string") await mongoose.connect(MONGO_URL); if (typeof db === "string") await mongoose.connect(db);
console.log("MongoDB Connected..."); console.log("MongoDB Connected...");
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === "string") console.error(err); if (typeof err === "string") console.error(err);
else if (err instanceof Error) { else if (err instanceof Error) console.error(err.message);
console.error(err.message);
console.log(MONGO_URL);
}
process.exit(1); process.exit(1);
} }
}; };
+15 -17
View File
@@ -1,34 +1,32 @@
import config from 'config' import config from "config";
import jwt from 'jsonwebtoken' import jwt from "jsonwebtoken";
import type { Request, Response, NextFunction } from 'express'; import type { Request, Response, NextFunction } from "express";
interface ResponseAndUser extends Request { user?: string } interface ResponseAndUser extends Request {
user?: string;
}
function auth(req: ResponseAndUser, res: Response, next: NextFunction) { function auth(req: ResponseAndUser, res: Response, next: NextFunction) {
// Get token from header // Get token from header
const token = req.header('x-auth-token'); const token = req.header("x-auth-token");
// Check if not token // Check if not token
if (!token) { if (!token) {
return res.status(401).json({ msg: 'No token, authorization denied' }); return res.status(401).json({ msg: "No token, authorization denied" });
} }
// Verify token // Verify token
try { try {
jwt.verify(token, config.get('jwtSecret'), (error, decoded) => { jwt.verify(token, config.get("jwtSecret"), (error, decoded) => {
if (error) { if (error) {
return res.status(401).json({ msg: 'Token is not valid' }); return res.status(401).json({ msg: "Token is not valid" });
} else { } else {
if (decoded && typeof decoded !== "string") if (decoded && typeof decoded !== "string") req.user = decoded?.user;
req.user = decoded?.user;
next(); next();
} }
}); });
} catch (err) { } catch (err) {
console.error('something wrong with auth middleware'); console.error("something wrong with auth middleware");
res.status(500).json({ msg: 'Server Error' }); res.status(500).json({ msg: "Server Error" });
} }
}
}; export default auth;
export default auth
+51 -71
View File
@@ -1,12 +1,10 @@
import express, { Request, Response } from "express";
import express, { Request, Response } from 'express'
import { check, validationResult } from "express-validator"; import { check, validationResult } from "express-validator";
import auth from "../../middleware/auth"; import auth from "../../middleware/auth";
import Post from "../../models/Post"; import Post from "../../models/Post";
import User from "../../models/User"; import User from "../../models/User";
import checkObjectId from "../../middleware/checkObjectId"; import checkObjectId from "../../middleware/checkObjectId";
import { isUserId } from '../../utils'; import { isUserId } from "../../utils";
const router = express.Router(); const router = express.Router();
@@ -36,22 +34,18 @@ router.post(
}); });
const post = await newPost.save(); const post = await newPost.save();
res.json(post); res.json(post);
} else {
throw new Error("Error finding the user");
} }
else { } else {
throw new Error('Error finding the user') throw new Error("Error finding the user");
}
}
else {
throw new Error('Error finding the user')
} }
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
} },
); );
// @route GET api/posts // @route GET api/posts
@@ -62,10 +56,8 @@ router.get("/", auth, async (req, res) => {
const posts = await Post.find().sort({ date: -1 }); const posts = await Post.find().sort({ date: -1 });
res.json(posts); res.json(posts);
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
}); });
@@ -83,10 +75,8 @@ router.get("/:id", auth, checkObjectId("id"), async (req, res) => {
res.json(post); res.json(post);
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
@@ -95,7 +85,10 @@ router.get("/:id", auth, checkObjectId("id"), async (req, res) => {
// @route DELETE api/posts/:id // @route DELETE api/posts/:id
// @desc Delete a post // @desc Delete a post
// @access Private // @access Private
router.delete("/:id", [auth, checkObjectId("id")], async (req: Request, res: Response) => { router.delete(
"/:id",
[auth, checkObjectId("id")],
async (req: Request, res: Response) => {
try { try {
const post = await Post.findOne({ _id: req.params.id }); const post = await Post.findOne({ _id: req.params.id });
@@ -108,22 +101,19 @@ router.delete("/:id", [auth, checkObjectId("id")], async (req: Request, res: Res
if (post.user.toString() !== req.user.id) { if (post.user.toString() !== req.user.id) {
return res.status(401).json({ msg: "User not authorized" }); return res.status(401).json({ msg: "User not authorized" });
} }
} } else {
else { throw new Error("Error in req.user");
throw new Error('Error in req.user')
} }
await post.deleteOne(); await post.deleteOne();
res.json({ msg: "Post removed" }); res.json({ msg: "Post removed" });
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
}); },
);
// @route PUT api/posts/like/:id // @route PUT api/posts/like/:id
// @desc Like a post // @desc Like a post
@@ -138,19 +128,17 @@ router.put("/like/:id", auth, checkObjectId("id"), async (req, res) => {
return res.status(400).json({ msg: "Post already liked" }); return res.status(400).json({ msg: "Post already liked" });
} }
const user: any = req.user.id const user: any = req.user.id;
// can't make string into ObjectID // can't make string into ObjectID
post.likes.unshift({ user }); post.likes.unshift({ user });
await post.save(); await post.save();
return res.json(post.likes) return res.json(post.likes);
}; }
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
}); });
@@ -164,29 +152,23 @@ router.put("/unlike/:id", auth, checkObjectId("id"), async (req, res) => {
// Check if the post has not yet been liked // Check if the post has not yet been liked
if (post && isUserId(req)) { if (post && isUserId(req)) {
if (!post.likes.some((like) => like.user?.toString() === req.user.id)) { if (!post.likes.some((like) => like.user?.toString() === req.user.id)) {
return res.status(400).json({ msg: "Post has not yet been liked" }); return res.status(400).json({ msg: "Post has not yet been liked" });
} }
// remove the like // remove the like
post.likes = post.likes.filter( post.likes = post.likes.filter(({ user }) => {
({ user }) => { if (user) return user.toString() !== req.user.id;
if (user) return false;
return user.toString() !== req.user.id });
return false
}
);
await post.save(); await post.save();
return res.json(post.likes); return res.json(post.likes);
} }
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
}); });
@@ -220,20 +202,15 @@ router.post(
post.comments.unshift(newComment as any); post.comments.unshift(newComment as any);
await post.save(); await post.save();
res.json(post.comments); res.json(post.comments);
} } else throw new Error("Error in finding post");
throw new Error('Error in finding post') } else throw new Error("Error in finding user");
} } else throw new Error("Error in parsing the req");
throw new Error('Error in finding user')
}
throw new Error('Error in parsing the req')
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
res.status(500).send("Server Error"); res.status(500).send("Server Error");
} }
} },
); );
// @route DELETE api/posts/comment/:id/:comment_id // @route DELETE api/posts/comment/:id/:comment_id
@@ -246,19 +223,24 @@ router.delete("/comment/:id/:comment_id", auth, async (req, res) => {
// Pull out comment // Pull out comment
if (post) { if (post) {
const comment = post.comments.find( const comment = post.comments.find(
(comment: any) => comment.id === req.params.comment_id (comment: any) => comment.id === req.params.comment_id,
); );
// Make sure comment exists // Make sure comment exists
if (!comment) { if (!comment) {
return res.status(404).json({ msg: "Comment does not exist" }); return res.status(404).json({ msg: "Comment does not exist" });
} }
// Check user // Check user
if ('user' in comment && comment.user && isUserId(req) && comment.user.toString() !== req.user.id) { if (
"user" in comment &&
comment.user &&
isUserId(req) &&
comment.user.toString() !== req.user.id
) {
return res.status(401).json({ msg: "User not authorized" }); return res.status(401).json({ msg: "User not authorized" });
} }
post.comments = post.comments.filter( post.comments = post.comments.filter(
({ id }: any) => id !== req.params.comment_id ({ id }: any) => id !== req.params.comment_id,
); );
await post.save(); await post.save();
@@ -266,12 +248,10 @@ router.delete("/comment/:id/:comment_id", auth, async (req, res) => {
return res.json(post.comments); return res.json(post.comments);
} }
} catch (err: unknown) { } catch (err: unknown) {
if (typeof err === 'string') if (typeof err === "string") console.error(err);
console.error(err) else if (err instanceof Error) console.error(err.message);
else if (err instanceof Error)
console.error(err.message);
return res.status(500).send("Server Error"); return res.status(500).send("Server Error");
} }
}); });
module.exports = router module.exports = router;
+1
View File
@@ -16,6 +16,7 @@ app.use("/api/posts", require("./routers/api/posts"));
// Serve static assets in production // Serve static assets in production
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === "production") {
console.log("in production");
app.use(express.static("client/build")); app.use(express.static("client/build"));
app.get("*", (req, res) => [ app.get("*", (req, res) => [
res.sendFile(path.resolve(__dirname, "client", "build", "index.html")), res.sendFile(path.resolve(__dirname, "client", "build", "index.html")),