Finished MUI for the most part
This commit is contained in:
Generated
+1224
-3148
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -5,8 +5,8 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/icons-material": "^5.14.3",
|
||||
"@mui/material": "^5.14.4",
|
||||
"@mui/icons-material": "^6.1.1",
|
||||
"@mui/material": "^6.1.1",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
|
||||
@@ -1,584 +0,0 @@
|
||||
/* Global Styles */
|
||||
:root {
|
||||
--primary-color: #17a2b8;
|
||||
--dark-color: #343a40;
|
||||
--light-color: #f4f4f4;
|
||||
--danger-color: #dc3545;
|
||||
--success-color: #28a745;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Raleway", sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
padding: 0 2rem;
|
||||
margin-top: 6rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
/* Text Styles*/
|
||||
.x-large {
|
||||
font-size: 4rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 3rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.text-dark {
|
||||
color: var(--dark-color);
|
||||
}
|
||||
|
||||
/* Padding */
|
||||
.p {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.p-1 {
|
||||
padding: 1rem;
|
||||
}
|
||||
.p-2 {
|
||||
padding: 2rem;
|
||||
}
|
||||
.p-3 {
|
||||
padding: 3rem;
|
||||
}
|
||||
.py {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.py-1 {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.py-2 {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
.py-3 {
|
||||
padding: 3rem 0;
|
||||
}
|
||||
|
||||
/* Margin */
|
||||
.m {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
.m-1 {
|
||||
margin: 1rem;
|
||||
}
|
||||
.m-2 {
|
||||
margin: 2rem;
|
||||
}
|
||||
.m-3 {
|
||||
margin: 3rem;
|
||||
}
|
||||
.my {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.my-1 {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.my-2 {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.my-3 {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
padding: 0.4rem 1.3rem;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-right: 0.5rem;
|
||||
transition: opacity 0.2s ease-in;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.1rem;
|
||||
text-align: center;
|
||||
margin: 0.3rem;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 0.8rem;
|
||||
margin: 1rem 0;
|
||||
opacity: 0.9;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.bg-primary,
|
||||
.badge-primary,
|
||||
.alert-primary {
|
||||
background: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-light,
|
||||
.bg-light,
|
||||
.badge-light,
|
||||
.alert-light {
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-dark,
|
||||
.bg-dark,
|
||||
.badge-dark,
|
||||
.alert-dark {
|
||||
background: var(--dark-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-danger,
|
||||
.bg-danger,
|
||||
.badge-danger,
|
||||
.alert-danger {
|
||||
background: var(--danger-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-success,
|
||||
.bg-success,
|
||||
.badge-success,
|
||||
.alert-success {
|
||||
background: var(--success-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-white,
|
||||
.bg-white,
|
||||
.badge-white,
|
||||
.alert-white {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border: #ccc solid 1px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.bg-light,
|
||||
.badge-light {
|
||||
border: #ccc solid 1px;
|
||||
}
|
||||
|
||||
.round-img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 1px;
|
||||
background: #ccc;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
/* Overlay */
|
||||
.dark-overlay {
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
.form .form-group {
|
||||
margin: 1.2rem 0;
|
||||
}
|
||||
|
||||
.form .form-text {
|
||||
display: block;
|
||||
margin-top: 0.3rem;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.form input[type="text"],
|
||||
.form input[type="email"],
|
||||
.form input[type="password"],
|
||||
.form input[type="date"],
|
||||
.form select,
|
||||
.form textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.4rem;
|
||||
font-size: 1.2rem;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.form input[type="submit"],
|
||||
button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.form .social-input {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.form .social-input i {
|
||||
padding: 0.5rem;
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.form .social-input i.fa-twitter {
|
||||
color: #38a1f3;
|
||||
}
|
||||
.form .social-input i.fa-facebook {
|
||||
color: #3b5998;
|
||||
}
|
||||
.form .social-input i.fa-instagram {
|
||||
color: #3f729b;
|
||||
}
|
||||
.form .social-input i.fa-youtube {
|
||||
color: #c4302b;
|
||||
}
|
||||
.form .social-input i.fa-linkedin {
|
||||
color: #0077b5;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background: var(--light-color);
|
||||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.7rem 2rem;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
border-bottom: solid 1px var(--primary-color);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.navbar ul {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: #fff;
|
||||
padding: 0.45rem;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.navbar a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.navbar .welcome span {
|
||||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
/* Landing Page */
|
||||
.landing {
|
||||
position: relative;
|
||||
background: url("./img/vimCheatSheet.jpg") no-repeat center center/cover;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.landing-inner {
|
||||
color: #fff;
|
||||
height: 100%;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Profiles Page */
|
||||
.profile {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 4fr 2fr;
|
||||
align-items: center;
|
||||
grid-gap: 2rem;
|
||||
padding: 1rem;
|
||||
line-height: 1.8;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Profile Page */
|
||||
.profile-grid {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"top top"
|
||||
"about about"
|
||||
"exp edu"
|
||||
"github github";
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.profile-top {
|
||||
grid-area: top;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-top img {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.profile-top .icons a {
|
||||
color: #fff;
|
||||
margin: 0 0.3rem;
|
||||
}
|
||||
|
||||
.profile-top .icons a:hover {
|
||||
color: var(--dark-color);
|
||||
}
|
||||
|
||||
.profile-about {
|
||||
grid-area: about;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-about .skills {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-exp {
|
||||
grid-area: exp;
|
||||
}
|
||||
|
||||
.profile-edu {
|
||||
grid-area: edu;
|
||||
}
|
||||
|
||||
.profile-exp h2,
|
||||
.profile-edu h2 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.profile-exp > div,
|
||||
.profile-edu > div {
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: #ccc 1px dotted;
|
||||
}
|
||||
|
||||
.profile-exp > div:last-child,
|
||||
.profile-edu > div:last-child {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.profile-exp p,
|
||||
.profile-edu p {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.profile-github {
|
||||
grid-area: github;
|
||||
}
|
||||
|
||||
.profile-github .repo {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.profile-github .repo > div:first-child {
|
||||
flex: 7;
|
||||
flex-basis: 70%;
|
||||
}
|
||||
|
||||
.profile-github > div:last-child {
|
||||
flex: 3;
|
||||
flex-basis: 20%;
|
||||
}
|
||||
|
||||
/* Posts Page */
|
||||
.post-form .post-form-header {
|
||||
background: var(--primary-color);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.post {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 4fr;
|
||||
grid-gap: 2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.post > div:first-child {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.post img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.post .comment-count {
|
||||
background: var(--light-color);
|
||||
color: var(--primary-color);
|
||||
padding: 0.1rem 0.2rem;
|
||||
border-radius: 5px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.post .post-date {
|
||||
color: #aaa;
|
||||
font-size: 0.8rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Mobile Styles */
|
||||
@media (max-width: 700px) {
|
||||
.container {
|
||||
margin-top: 8rem;
|
||||
}
|
||||
|
||||
.hide-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Text Styles */
|
||||
.x-large {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navbar ul {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.navbar h1 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.navbar .welcome {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Profiles Page */
|
||||
.profile {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile ul {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Profile Page */
|
||||
|
||||
.profile-top img,
|
||||
.profile img {
|
||||
width: 200px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.profile-grid {
|
||||
grid-template-areas:
|
||||
"top"
|
||||
"about"
|
||||
"exp"
|
||||
"edu"
|
||||
"github";
|
||||
}
|
||||
|
||||
.profile-about .skills {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dash-buttons a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.post {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.post a,
|
||||
.post button {
|
||||
padding: 0.3rem 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-wrapper {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
right: 2rem;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
.datePicker :hover {
|
||||
border-color: "#212121";
|
||||
}
|
||||
.datePicker :focus {
|
||||
border-color: "#1976d2";
|
||||
border-width: "2px";
|
||||
}
|
||||
.datePicker{
|
||||
color:"red";
|
||||
background:"red";
|
||||
}
|
||||
|
||||
.colormebaby{
|
||||
background-color:"red";
|
||||
color:"red"
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import * as React from "react";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Grid from "@mui/material/Grid2";
|
||||
import Box from "@mui/material/Box";
|
||||
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
||||
import Typography from "@mui/material/Typography";
|
||||
@@ -54,7 +54,7 @@ export default function SignUp() {
|
||||
</Typography>
|
||||
<Box component="form" noValidate onSubmit={handleSubmit} sx={{ mt: 3 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
name="name"
|
||||
required
|
||||
@@ -64,7 +64,7 @@ export default function SignUp() {
|
||||
autoFocus
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
required
|
||||
fullWidth
|
||||
@@ -73,7 +73,7 @@ export default function SignUp() {
|
||||
name="email"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
required
|
||||
fullWidth
|
||||
@@ -83,7 +83,7 @@ export default function SignUp() {
|
||||
id="password"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
required
|
||||
fullWidth
|
||||
@@ -103,7 +103,7 @@ export default function SignUp() {
|
||||
Sign Up
|
||||
</Button>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item>
|
||||
<Grid>
|
||||
Already have an account? <Link to={"/login"}>Sign in</Link>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -6,6 +6,7 @@ import Experience from "./Experience";
|
||||
import Education from "./Education";
|
||||
import { getCurrentProfile, deleteAccount } from "../../actions/profile";
|
||||
import { Box, Button, Typography } from "@mui/material";
|
||||
import { compose } from "redux";
|
||||
|
||||
const Dashboard = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -19,13 +20,14 @@ const Dashboard = () => {
|
||||
const profile = useAppSelector((state) => state.profile.profile);
|
||||
return (
|
||||
<Box
|
||||
component="main"
|
||||
justifyContent="center"
|
||||
flexDirection="column"
|
||||
minHeight="50vh"
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
gap="1rem"
|
||||
sx={{
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
minHeight: "50vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "1rem",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h3" component="h2">
|
||||
Dashboard{" "}
|
||||
@@ -38,7 +40,7 @@ const Dashboard = () => {
|
||||
<DashboardActions />
|
||||
<Experience experience={profile.experience} />
|
||||
<Education education={profile.education} />
|
||||
<Box sx={{ marginTop: "10vh" }}>
|
||||
<Box sx={{ marginTop: "2vh" }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
|
||||
@@ -4,7 +4,12 @@ import { Link } from "react-router-dom";
|
||||
|
||||
const DashboardActions = () => {
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: { xs: "grid", md: "flex" },
|
||||
rowGap: { xs: "5px" },
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
component={Link}
|
||||
to="/edit-profile"
|
||||
|
||||
@@ -21,19 +21,26 @@ const Education = ({ education }: { education: EducationType[] }) => {
|
||||
const educations = education.map((edu) => (
|
||||
<TableRow key={edu._id}>
|
||||
<TableCell
|
||||
// style={{
|
||||
// wordWrap: "break-word",
|
||||
// }}
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{edu.school}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
// style={{ wordWrap: "break-word" }}
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{edu.degree}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
// style={{ wordWrap: "break-word" }}
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{formatDate(edu.from)} - {edu.to ? formatDate(edu.to) : "Now"}
|
||||
</TableCell>
|
||||
@@ -56,13 +63,7 @@ const Education = ({ education }: { education: EducationType[] }) => {
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h2">Education Credentials</Typography>
|
||||
<Table
|
||||
// style={{
|
||||
// tableLayout: "fixed",
|
||||
// width: "50%",
|
||||
// alignSelf: "left",
|
||||
// }}
|
||||
>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>School</TableCell>
|
||||
|
||||
@@ -20,9 +20,28 @@ const Experience = ({ experience }: { experience: ExperienceType[] }) => {
|
||||
if (!experience) return <></>;
|
||||
const experiences = experience.map((exp) => (
|
||||
<TableRow key={exp._id}>
|
||||
<TableCell>{exp.company}</TableCell>
|
||||
<TableCell>{exp.title}</TableCell>
|
||||
<TableCell>
|
||||
<TableCell
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{exp.company}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{exp.title}
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{formatDate(exp.from)} - {exp.to ? formatDate(exp.to) : "Now"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
|
||||
@@ -148,7 +148,6 @@ const Navbar = () => {
|
||||
Logout
|
||||
</a>
|
||||
</MenuItem>
|
||||
,
|
||||
</div>
|
||||
) : (
|
||||
guestLinks.map((el) => (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Box, Button, Container, TextField, Typography } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { createAlert } from "../../actions/alert";
|
||||
import { addComment } from "../../actions/post";
|
||||
import { useAppDispatch } from "../../utils/hooks";
|
||||
|
||||
@@ -18,8 +19,14 @@ const CommentForm = ({ postId }: { postId: string }) => {
|
||||
gap="1rem"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
dispatch(addComment(postId, { text }));
|
||||
setText("");
|
||||
if (text.length > 250) {
|
||||
dispatch(
|
||||
createAlert("Comment longer than 250 characters", "danger"),
|
||||
);
|
||||
} else {
|
||||
dispatch(addComment(postId, { text }));
|
||||
setText("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
|
||||
@@ -40,7 +40,12 @@ const CommentItem = ({
|
||||
</Button>
|
||||
)}
|
||||
<CardContent>
|
||||
<Typography variant="subtitle1">{text}</Typography>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
sx={{ textWrap: "wrap", wordBreak: "break-word" }}
|
||||
>
|
||||
{text}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Container>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Box, Button, Container, TextField, Typography } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { createAlert } from "../../actions/alert";
|
||||
import { addPost } from "../../actions/post";
|
||||
import { useAppDispatch } from "../../utils/hooks";
|
||||
|
||||
const PostForm = () => {
|
||||
const [text, setText] = useState("");
|
||||
const dispatch = useAppDispatch();
|
||||
const handleSumbit = {};
|
||||
return (
|
||||
<Container>
|
||||
<Typography>Say Something...</Typography>
|
||||
@@ -18,8 +18,12 @@ const PostForm = () => {
|
||||
sx={{ mt: 3, mb: 3 }}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
dispatch(addPost({ text }));
|
||||
setText("");
|
||||
if (text.length > 250) {
|
||||
dispatch(createAlert("Post longer than 250 characters", "danger"));
|
||||
} else {
|
||||
dispatch(addPost({ text }));
|
||||
setText("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
@@ -27,7 +31,9 @@ const PostForm = () => {
|
||||
label="Create a post"
|
||||
fullWidth
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
onChange={(e) => {
|
||||
return setText(e.target.value);
|
||||
}}
|
||||
multiline
|
||||
rows={3}
|
||||
required
|
||||
|
||||
@@ -6,14 +6,12 @@ import { Post } from "../../types";
|
||||
import { useAppDispatch, useAppSelector } from "../../utils/hooks";
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
Container,
|
||||
Table,
|
||||
TableCell,
|
||||
TableRow,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import ThumbDownIcon from "@mui/icons-material/ThumbDown";
|
||||
@@ -36,45 +34,42 @@ const PostItem = ({
|
||||
subheader={formatDate(date)}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography variant="subtitle1">{text}</Typography>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
sx={{ textWrap: "wrap", wordBreak: "break-word" }}
|
||||
>
|
||||
{text}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Table>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Button onClick={async () => await dispatch(addLike(_id))}>
|
||||
<ThumbUpIcon />
|
||||
</Button>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography display="inline-flex" variant="button">
|
||||
{likes.length}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button onClick={async () => await dispatch(removeLike(_id))}>
|
||||
<ThumbDownIcon />
|
||||
</Button>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button component={Link} to={`/posts/${_id}`}>
|
||||
<Typography>Comments </Typography>
|
||||
</Button>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography display="inline-flex" variant="button">
|
||||
{comments.length}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{!auth.loading && auth.user !== null && user === auth.user._id && (
|
||||
<Button onClick={async () => await dispatch(deletePost(_id))}>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</Table>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-evenly",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Button onClick={async () => await dispatch(addLike(_id))}>
|
||||
<ThumbUpIcon />
|
||||
</Button>
|
||||
<Typography display="inline-flex" variant="button">
|
||||
{likes.length}
|
||||
</Typography>
|
||||
<Button onClick={async () => await dispatch(removeLike(_id))}>
|
||||
<ThumbDownIcon />
|
||||
</Button>
|
||||
<Button component={Link} to={`/posts/${_id}`}>
|
||||
<Typography>Comments </Typography>
|
||||
</Button>
|
||||
<Typography display="inline-flex" variant="button">
|
||||
{comments.length}
|
||||
</Typography>
|
||||
{!auth.loading && auth.user !== null && user === auth.user._id && (
|
||||
<Button onClick={async () => await dispatch(deletePost(_id))}>
|
||||
<DeleteIcon />
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import styled from "@emotion/styled";
|
||||
import {
|
||||
Button,
|
||||
Box,
|
||||
Container,
|
||||
TextField,
|
||||
Typography,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
import { Button, Box, Container, TextField, Typography } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { createAlert } from "../../actions/alert";
|
||||
import { addEducation } from "../../actions/profile";
|
||||
import { useAppDispatch } from "../../utils/hooks";
|
||||
|
||||
@@ -51,6 +44,21 @@ const AddEducation = () => {
|
||||
const onChange = (
|
||||
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,
|
||||
) => setFormData({ ...formData, [event.target.name]: event.target.value });
|
||||
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
if (formData.degree.length > 50) {
|
||||
dispatch(createAlert("Degree is longer 50 characters", "danger"));
|
||||
} else if (formData.fieldofstudy.length > 50) {
|
||||
dispatch(createAlert("Field of study is longer 50 characters", "danger"));
|
||||
} else if (formData.description.length > 250) {
|
||||
dispatch(
|
||||
createAlert("Description name is longer 250 characters", "danger"),
|
||||
);
|
||||
} else if (formData.school.length > 50) {
|
||||
dispatch(createAlert("School name is longer 50 characters", "danger"));
|
||||
} else
|
||||
await dispatch(addEducation(formData)).then(() => navigate("/dashboard"));
|
||||
};
|
||||
|
||||
return (
|
||||
<Container maxWidth="sm">
|
||||
@@ -68,12 +76,7 @@ const AddEducation = () => {
|
||||
noValidate
|
||||
maxWidth="500px"
|
||||
sx={{ mt: 3 }}
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
await dispatch(addEducation(formData)).then(() =>
|
||||
navigate("/dashboard"),
|
||||
);
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
<TextField
|
||||
name="school"
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { Container } from "@mui/system";
|
||||
import React, { useState } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { createAlert } from "../../actions/alert";
|
||||
import { addExperience } from "../../actions/profile";
|
||||
import { useAppDispatch } from "../../utils/hooks";
|
||||
|
||||
@@ -69,9 +70,30 @@ const AddExperience = () => {
|
||||
sx={{ mt: 3 }}
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
await dispatch(addExperience(formData)).then(() =>
|
||||
navigate("/dashboard"),
|
||||
);
|
||||
if (formData.description.length > 250) {
|
||||
dispatch(
|
||||
createAlert("Job description is longer 250 characters", "danger"),
|
||||
);
|
||||
} else if (formData.location.length > 50) {
|
||||
dispatch(
|
||||
createAlert("Location is longer than 50 characters", "danger"),
|
||||
);
|
||||
} else if (formData.title.length > 50) {
|
||||
dispatch(
|
||||
createAlert("Job title is longer than 50 characters", "danger"),
|
||||
);
|
||||
} else if (formData.company.length > 50) {
|
||||
dispatch(
|
||||
createAlert(
|
||||
"Company name is longer than 50 characters",
|
||||
"danger",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
await dispatch(addExperience(formData)).then(() =>
|
||||
navigate("/dashboard"),
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
|
||||
@@ -2,16 +2,16 @@ import {
|
||||
Button,
|
||||
Box,
|
||||
Container,
|
||||
CssBaseline,
|
||||
Grid,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import React, { Fragment, useState, useEffect } from "react";
|
||||
import Grid from "@mui/material/Grid2";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Link, useMatch, useNavigate } from "react-router-dom";
|
||||
import { createAlert } from "../../actions/alert";
|
||||
import { createProfile, getCurrentProfile } from "../../actions/profile";
|
||||
import { useAppDispatch, useAppSelector } from "../../utils/hooks";
|
||||
|
||||
@@ -86,28 +86,52 @@ const ProfileForm = () => {
|
||||
const linkedin = data.get("linkedin") as string;
|
||||
const instagram = data.get("instagram") as string;
|
||||
const status = data.get("status") as string;
|
||||
await dispatch(
|
||||
createProfile(
|
||||
{
|
||||
website,
|
||||
location,
|
||||
skills,
|
||||
githubusername,
|
||||
company,
|
||||
bio,
|
||||
twitter,
|
||||
facebook,
|
||||
youtube,
|
||||
linkedin,
|
||||
instagram,
|
||||
status,
|
||||
},
|
||||
editing,
|
||||
),
|
||||
).then((res) => {
|
||||
console.log(res);
|
||||
if (!editing) navigate("/dashboard");
|
||||
});
|
||||
if (facebook?.length > 100) {
|
||||
dispatch(createAlert("Facebook link is longer 100 characters", "danger"));
|
||||
} else if (linkedin?.length > 100) {
|
||||
dispatch(createAlert("LinkedIn link is longer 100 characters", "danger"));
|
||||
} else if (youtube?.length > 100) {
|
||||
dispatch(createAlert("Youtube link is longer 100 characters", "danger"));
|
||||
} else if (instagram?.length > 100) {
|
||||
dispatch(
|
||||
createAlert("Instagram link is longer 100 characters", "danger"),
|
||||
);
|
||||
} else if (website?.length > 100) {
|
||||
dispatch(createAlert("Website link is longer 100 characters", "danger"));
|
||||
} else if (skills.length > 100) {
|
||||
dispatch(createAlert("Skills is longer 100 characters", "danger"));
|
||||
} else if (location?.length > 50) {
|
||||
dispatch(createAlert("Location is longer 100 characters", "danger"));
|
||||
} else if (githubusername?.length > 50) {
|
||||
dispatch(
|
||||
createAlert("Github username is longer 50 characters", "danger"),
|
||||
);
|
||||
} else if (company?.length > 50) {
|
||||
dispatch(createAlert("Company name is longer 50 characters", "danger"));
|
||||
} else if (bio?.length > 250) {
|
||||
dispatch(createAlert("Bio name is longer 250 characters", "danger"));
|
||||
} else
|
||||
await dispatch(
|
||||
createProfile(
|
||||
{
|
||||
website,
|
||||
location,
|
||||
skills,
|
||||
githubusername,
|
||||
company,
|
||||
bio,
|
||||
twitter,
|
||||
facebook,
|
||||
youtube,
|
||||
linkedin,
|
||||
instagram,
|
||||
status,
|
||||
},
|
||||
editing,
|
||||
),
|
||||
).then(() => {
|
||||
if (!editing) navigate("/dashboard");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -123,48 +147,48 @@ const ProfileForm = () => {
|
||||
<Typography variant="body2">* = required field</Typography>
|
||||
<Box component="form" noValidate onSubmit={onSubmit} sx={{ mt: 3 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField name="company" fullWidth label="Company" autoFocus />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<Typography paddingY="1rem">
|
||||
Could be your own company or one you work for
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField name="website" fullWidth label="Website" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<Typography paddingY="1rem">
|
||||
Could be your own a or a company website
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField name="location" fullWidth label="Location" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<Typography paddingY="1rem">
|
||||
City & state suggest(eg. Boston MA)
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField name="skills" required fullWidth label="Skills" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<Typography>
|
||||
Please use comma separeted values (eg. HTML, CSS, JavaScript, PHP)
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField name="githubUser" fullWidth label="Github Username" />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<Typography>
|
||||
If you want your latest repositories, add a Github link and
|
||||
include your username
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<InputLabel id="status">Status *</InputLabel>
|
||||
<Select
|
||||
fullWidth
|
||||
@@ -187,15 +211,15 @@ const ProfileForm = () => {
|
||||
<MenuItem value="Other">Other</MenuItem>
|
||||
</Select>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<Typography paddingTop="2.3rem">
|
||||
Select Profesional Status
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<Typography>Tell us a little about yourself</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
name="bio"
|
||||
multiline
|
||||
@@ -204,7 +228,7 @@ const ProfileForm = () => {
|
||||
label="A short bio of yourself"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => toggleSocialInputs(!displaySocialInputs)}
|
||||
@@ -214,33 +238,33 @@ const ProfileForm = () => {
|
||||
</Grid>
|
||||
{displaySocialInputs ? (
|
||||
<>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField fullWidth name="twitter" label="Twitter URL" />
|
||||
</Grid>
|
||||
<Grid item xs={6}></Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}></Grid>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField fullWidth name="facebook" label="FaceBook URL" />
|
||||
</Grid>
|
||||
<Grid item xs={6}></Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}></Grid>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField fullWidth name="youtube" label="YouTube URL" />
|
||||
</Grid>
|
||||
<Grid item xs={6}></Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}></Grid>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField fullWidth name="linkedin" label="Linkedin URL" />
|
||||
</Grid>
|
||||
<Grid item xs={6}></Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid size={{ xs: 6 }}></Grid>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField fullWidth name="instagram" label="Instagram URL" />
|
||||
</Grid>
|
||||
</>
|
||||
) : null}
|
||||
<Grid item xs={8}>
|
||||
<Grid size={{ xs: 8 }}>
|
||||
<Button variant="contained" type="submit">
|
||||
Submit Changes
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<Grid size={{ xs: 2 }}>
|
||||
<Button variant="outlined">
|
||||
<Link
|
||||
style={{ color: "inherit", textDecoration: "none" }}
|
||||
|
||||
@@ -9,7 +9,8 @@ import ProfileGithub from "./ProfileGithub";
|
||||
import { getProfileById } from "../../actions/profile";
|
||||
import { useAppDispatch, useAppSelector } from "../../utils/hooks";
|
||||
import { EducationType, ExperienceType } from "../../types";
|
||||
import { Box, Button, Card, Paper, Typography } from "@mui/material";
|
||||
import { Box, Button, Card, Container, Paper, Typography } from "@mui/material";
|
||||
import Grid from "@mui/material/Grid2";
|
||||
|
||||
const Profile = () => {
|
||||
const profile = useAppSelector((state) => state.profile.profile);
|
||||
@@ -25,26 +26,54 @@ const Profile = () => {
|
||||
}, [dispatch, id]);
|
||||
|
||||
return (
|
||||
<Box display="flex" flexDirection="column" alignItems="center">
|
||||
<>
|
||||
{profile === null ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<>
|
||||
<Button component={Link} to="/profiles">
|
||||
Back To Profiles
|
||||
</Button>
|
||||
{auth.isAuthenticated &&
|
||||
auth.loading === false &&
|
||||
auth.user !== null &&
|
||||
auth.user._id === profile.user._id && (
|
||||
<Button component={Link} to="/edit-profile">
|
||||
Edit Profile
|
||||
</Button>
|
||||
)}
|
||||
<Paper elevation={9} sx={{ width: "90%" }}>
|
||||
<ProfileTop profile={profile} />
|
||||
<ProfileAbout profile={profile} />
|
||||
<Box>
|
||||
<Paper sx={{ display: "grid", justifyItems: "center", marginY: "5px" }}>
|
||||
<div>
|
||||
<Button
|
||||
variant="contained"
|
||||
component={Link}
|
||||
to="/profiles"
|
||||
sx={{
|
||||
width: "70px",
|
||||
margin: "5px",
|
||||
}}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
{auth.isAuthenticated &&
|
||||
auth.loading === false &&
|
||||
auth.user !== null &&
|
||||
auth.user._id === profile.user._id && (
|
||||
<Button
|
||||
component={Link}
|
||||
to="/edit-profile"
|
||||
variant="outlined"
|
||||
sx={{
|
||||
width: "70px",
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
rowSpacing={"30px"}
|
||||
sx={{
|
||||
marginX: "20%",
|
||||
}}
|
||||
>
|
||||
<Grid size={{ sm: 12, lg: 4 }}>
|
||||
<ProfileTop profile={profile} />
|
||||
</Grid>
|
||||
<Grid size={{ sm: 12, lg: 8 }}>
|
||||
<ProfileAbout profile={profile} />
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, md: 6 }}>
|
||||
<Typography variant="h2">Experience</Typography>
|
||||
{profile.experience.length > 0 ? (
|
||||
<>
|
||||
@@ -58,8 +87,8 @@ const Profile = () => {
|
||||
) : (
|
||||
<Typography variant="h4">No experience credentials</Typography>
|
||||
)}
|
||||
</Box>
|
||||
<Box>
|
||||
</Grid>
|
||||
<Grid size={6}>
|
||||
<Typography variant="h2">Education</Typography>
|
||||
{profile.education.length > 0 ? (
|
||||
<>
|
||||
@@ -73,14 +102,14 @@ const Profile = () => {
|
||||
) : (
|
||||
<Typography variant="h4">No education credentials</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Grid>
|
||||
{profile.githubusername && (
|
||||
<ProfileGithub username={profile.githubusername} />
|
||||
)}
|
||||
</Paper>
|
||||
</>
|
||||
</Grid>
|
||||
</Paper>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Box, List, ListItem, Typography } from "@mui/material";
|
||||
import React, { Fragment } from "react";
|
||||
import { ProfileType } from "../../types";
|
||||
|
||||
@@ -11,21 +11,32 @@ const ProfileAbout = ({
|
||||
}: {
|
||||
profile: ProfileType;
|
||||
}) => (
|
||||
<Box>
|
||||
<Box sx={{ textWrap: "wrap", maxWidth: "100%" }}>
|
||||
{bio && (
|
||||
<>
|
||||
<Typography>{name.trim().split(" ")[0]}s Bio</Typography>
|
||||
<Typography>{bio}</Typography>
|
||||
<Typography color="info" variant="h5">
|
||||
<b>{name.trim().split(" ")[0]}'s Bio</b>
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{bio}
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
<Typography>Skill Set</Typography>
|
||||
<Box>
|
||||
<Typography color="info" variant="h5">
|
||||
<b>Skill Set</b>
|
||||
</Typography>
|
||||
<List>
|
||||
{skills.map((skill, index) => (
|
||||
<Box key={index}>
|
||||
<ListItem key={index}>
|
||||
<Typography>{skill}</Typography>
|
||||
</Box>
|
||||
</ListItem>
|
||||
))}
|
||||
</Box>
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Paper, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { EducationType } from "../../types";
|
||||
import formatDate from "../../utils/formatDate";
|
||||
@@ -8,15 +8,49 @@ const ProfileEducation = ({
|
||||
}: {
|
||||
education: EducationType;
|
||||
}) => (
|
||||
<Box>
|
||||
<Typography variant="h3">{school}</Typography>
|
||||
<Typography>
|
||||
<Paper elevation={12} sx={{ margin: "10px", padding: "4px" }}>
|
||||
<Typography
|
||||
variant="h4"
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{school}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{formatDate(from)} - {to ? formatDate(to) : "Now"}
|
||||
</Typography>
|
||||
<Typography>Degree: {degree}</Typography>
|
||||
<Typography>Field Of Study: {fieldofstudy}</Typography>
|
||||
<Typography>Description: {description}</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>Degree:</b> {degree}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>Field Of Study:</b> {fieldofstudy}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>Description:</b> {description}
|
||||
</Typography>
|
||||
</Paper>
|
||||
);
|
||||
|
||||
export default ProfileEducation;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { Paper, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { ExperienceType } from "../../types";
|
||||
import formatDate from "../../utils/formatDate";
|
||||
@@ -8,15 +8,43 @@ const ProfileExperience = ({
|
||||
}: {
|
||||
experience: ExperienceType;
|
||||
}) => (
|
||||
<Box>
|
||||
<Typography variant="h3">{company}</Typography>
|
||||
<Paper elevation={12} sx={{ margin: "10px", padding: "4px" }}>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>{company}</b>
|
||||
</Typography>
|
||||
<Typography>
|
||||
{formatDate(from)} - {to ? formatDate(to) : "Now"}
|
||||
</Typography>
|
||||
<Typography>Position: {title}</Typography>
|
||||
<Typography>Location: {location}</Typography>
|
||||
<Typography>Description: {description}</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>Position:</b> {title}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>Location:</b> {location}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textWrap: "wrap",
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
<b>Description:</b> {description}
|
||||
</Typography>
|
||||
</Paper>
|
||||
);
|
||||
|
||||
export default ProfileExperience;
|
||||
|
||||
@@ -13,10 +13,10 @@ const ProfileGithub = ({ username }: { username: string }) => {
|
||||
}, [dispatch, username]);
|
||||
|
||||
return (
|
||||
<div className="profile-github">
|
||||
<h2 className="text-primary my-1">Github Repos</h2>
|
||||
<div>
|
||||
<h2>Github Repos</h2>
|
||||
{repos.map((repo) => (
|
||||
<div key={repo.id} className="repo bg-white p-1 my-1">
|
||||
<div key={repo.id}>
|
||||
<div>
|
||||
<h4>
|
||||
<a href={repo.html_url} target="_blank" rel="noopener noreferrer">
|
||||
@@ -27,13 +27,9 @@ const ProfileGithub = ({ username }: { username: string }) => {
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
<li className="badge badge-primary">
|
||||
Stars: {repo.stargazers_count}
|
||||
</li>
|
||||
<li className="badge badge-dark">
|
||||
Watchers: {repo.watchers_count}
|
||||
</li>
|
||||
<li className="badge badge-light">Forks: {repo.forks_count}</li>
|
||||
<li>Stars: {repo.stargazers_count}</li>
|
||||
<li>Watchers: {repo.watchers_count}</li>
|
||||
<li>Forks: {repo.forks_count}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BorderAll } from "@mui/icons-material";
|
||||
import { Avatar, Box, Card, CardHeader, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { ProfileType } from "../../types";
|
||||
@@ -14,19 +15,18 @@ const ProfileTop = ({
|
||||
}: {
|
||||
profile: ProfileType;
|
||||
}) => {
|
||||
console.log(avatar)
|
||||
return (
|
||||
<>
|
||||
<img className="round-img my-1" src={avatar} alt="" />
|
||||
<Typography variant="h1">{name}</Typography>
|
||||
<Typography>
|
||||
<img src={avatar} alt="" />
|
||||
<Typography variant="h2">{name}</Typography>
|
||||
<Typography sx={{ textWrap: "wrap" }}>
|
||||
{status} {company ? <span> at {company}</span> : null}
|
||||
</Typography>
|
||||
<Typography>{location ? <span>{location}</span> : null}</Typography>
|
||||
{location ? <Typography>{location}</Typography> : null}
|
||||
<Box>
|
||||
{website ? (
|
||||
<a href={website} target="_blank" rel="noopener noreferrer">
|
||||
<i className="fas fa-globe fa-2x" />
|
||||
<i>{website}</i>
|
||||
</a>
|
||||
) : null}
|
||||
{social
|
||||
@@ -38,8 +38,9 @@ const ProfileTop = ({
|
||||
href={value}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ display: "block" }}
|
||||
>
|
||||
<i className={`fab fa-${key} fa-2x`}></i>
|
||||
<i>{value}</i>
|
||||
</a>
|
||||
))
|
||||
: null}
|
||||
|
||||
@@ -22,18 +22,21 @@ const ProfileItem = ({
|
||||
profile: ProfileType;
|
||||
}) => {
|
||||
return (
|
||||
<Paper sx={{ padding: "100px" }}>
|
||||
<Paper sx={{ width: "250px", paddingX: "10px" }}>
|
||||
<img src={avatar} alt="" />
|
||||
<Box>
|
||||
<Typography>{name}</Typography>
|
||||
<Typography>
|
||||
{status} {company && <span> at {company}</span>}
|
||||
</Typography>
|
||||
<Typography>{location && <span>{location}</span>}</Typography>
|
||||
<Button component={Link} to={`/profile/${_id}`}>
|
||||
View Profile
|
||||
</Button>
|
||||
</Box>
|
||||
<Typography color="info">
|
||||
<b>{name}</b>
|
||||
</Typography>
|
||||
<Typography>
|
||||
{status} {company && <span> at {company}</span>}
|
||||
</Typography>
|
||||
<Typography>{location && <span>{location}</span>}</Typography>
|
||||
<Button component={Link} to={`/profile/${_id}`} variant="outlined">
|
||||
View Profile
|
||||
</Button>
|
||||
<Typography color="info">
|
||||
<b>Skills:</b>
|
||||
</Typography>
|
||||
<List>
|
||||
{skills.slice(0, 4).map((skill, index) => (
|
||||
<ListItemText key={index}>{skill}</ListItemText>
|
||||
|
||||
@@ -17,28 +17,33 @@ const Profiles = () => {
|
||||
|
||||
const { profiles, loading } = useAppSelector((state) => state.profile);
|
||||
return (
|
||||
<Container maxWidth="sm">
|
||||
<Box display="flex" flexDirection="column" alignItems="center">
|
||||
{loading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<>
|
||||
<Typography variant="h2">Developers</Typography>
|
||||
<Typography variant="h6">
|
||||
Browse and connect with developers
|
||||
</Typography>
|
||||
<Box display="flex" flexDirection="row">
|
||||
{profiles.length > 0 && Array.isArray(profiles) ? (
|
||||
profiles.map((profile) => (
|
||||
<ProfileItem key={profile._id} profile={profile} />
|
||||
))
|
||||
) : (
|
||||
<Typography>No profiles found...</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
<Container>
|
||||
{loading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<>
|
||||
<Typography variant="h2">Developers</Typography>
|
||||
<Typography variant="h6">
|
||||
Browse and connect with developers
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "left",
|
||||
gap: "10px",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{profiles.length > 0 && Array.isArray(profiles) ? (
|
||||
profiles.map((profile) => (
|
||||
<ProfileItem key={profile._id} profile={profile} />
|
||||
))
|
||||
) : (
|
||||
<Typography>No profiles found...</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 292 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.1 MiB |
@@ -2,7 +2,6 @@ import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
|
||||
import "./App2.css";
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById("root") as HTMLElement,
|
||||
);
|
||||
|
||||
+96
-106
@@ -1,41 +1,41 @@
|
||||
import express from 'express';
|
||||
import axios from 'axios';
|
||||
import config from 'config';
|
||||
import express from "express";
|
||||
import axios from "axios";
|
||||
import config from "config";
|
||||
|
||||
import auth from '../../middleware/auth';
|
||||
import { check, validationResult } from 'express-validator';
|
||||
import auth from "../../middleware/auth";
|
||||
import { check, validationResult } from "express-validator";
|
||||
|
||||
// bring in normalize to give us a proper url, regardless of what user entered
|
||||
import normalize from 'normalize-url';
|
||||
import checkObjectId from '../../middleware/checkObjectId';
|
||||
import normalize from "normalize-url";
|
||||
import checkObjectId from "../../middleware/checkObjectId";
|
||||
|
||||
import Profile from '../../models/Profile';
|
||||
import User from '../../models/User';
|
||||
import Post from '../../models/Post';
|
||||
import { isUserId } from '../../utils';
|
||||
import Profile from "../../models/Profile";
|
||||
import User from "../../models/User";
|
||||
import Post from "../../models/Post";
|
||||
import { isUserId } from "../../utils";
|
||||
const router = express.Router();
|
||||
// @route GET api/profile/me
|
||||
// @desc Get current users profile
|
||||
// @access Private
|
||||
router.get('/me', auth, async (req, res) => {
|
||||
router.get("/me", auth, async (req, res) => {
|
||||
try {
|
||||
if (isUserId(req)) {
|
||||
const profile = await Profile.findOne({
|
||||
user: req.user.id
|
||||
}).populate('user', ['name', 'avatar']);
|
||||
user: req.user.id,
|
||||
}).populate("user", ["name", "avatar"]);
|
||||
|
||||
if (!profile) {
|
||||
return res.status(400).json({ msg: 'There is no profile for this user' });
|
||||
return res
|
||||
.status(400)
|
||||
.json({ msg: "There is no profile for this user" });
|
||||
}
|
||||
|
||||
res.json(profile);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
res.status(500).send("Server Error");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,10 +43,10 @@ router.get('/me', auth, async (req, res) => {
|
||||
// @desc Create or update user profile
|
||||
// @access Private
|
||||
router.post(
|
||||
'/',
|
||||
"/",
|
||||
auth,
|
||||
check('status', 'Status is required').notEmpty(),
|
||||
check('skills', 'Skills is required').notEmpty(),
|
||||
check("status", "Status is required").notEmpty(),
|
||||
check("skills", "Skills is required").notEmpty(),
|
||||
async (req, res) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
@@ -71,17 +71,23 @@ router.post(
|
||||
const profileFields = {
|
||||
user: req.user.id,
|
||||
website:
|
||||
website && website !== ''
|
||||
website && website !== ""
|
||||
? normalize(website, { forceHttps: true })
|
||||
: '',
|
||||
: "",
|
||||
skills: Array.isArray(skills)
|
||||
? skills
|
||||
: skills.split(',').map((skill: string) => ' ' + skill.trim()),
|
||||
...rest
|
||||
: skills.split(",").map((skill: string) => " " + skill.trim()),
|
||||
...rest,
|
||||
};
|
||||
|
||||
// Build socialFields object
|
||||
const socialFields: { [key: string]: any } = { youtube, twitter, instagram, linkedin, facebook };
|
||||
const socialFields: { [key: string]: any } = {
|
||||
youtube,
|
||||
twitter,
|
||||
instagram,
|
||||
linkedin,
|
||||
facebook,
|
||||
};
|
||||
|
||||
// normalize social fields to ensure valid url
|
||||
for (const [key, value] of Object.entries(socialFields)) {
|
||||
@@ -96,33 +102,29 @@ router.post(
|
||||
let profile = await Profile.findOneAndUpdate(
|
||||
{ user: req.user.id },
|
||||
{ $set: profileFields },
|
||||
{ new: true, upsert: true, setDefaultsOnInsert: true }
|
||||
{ new: true, upsert: true, setDefaultsOnInsert: true },
|
||||
);
|
||||
return res.json(profile);
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
return res.status(500).send('Server Error');
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
return res.status(500).send("Server Error");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// @route GET api/profile
|
||||
// @desc Get all profiles
|
||||
// @access Public
|
||||
router.get('/', async (req, res) => {
|
||||
router.get("/", async (req, res) => {
|
||||
try {
|
||||
const profiles = await Profile.find().populate('user', ['name', 'avatar']);
|
||||
const profiles = await Profile.find().populate("user", ["name", "avatar"]);
|
||||
res.json(profiles);
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
res.status(500).send("Server Error");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -130,31 +132,29 @@ router.get('/', async (req, res) => {
|
||||
// @desc Get profile by user ID
|
||||
// @access Public
|
||||
router.get(
|
||||
'/user/:user_id',
|
||||
checkObjectId('user_id'),
|
||||
"/user/:user_id",
|
||||
checkObjectId("user_id"),
|
||||
async ({ params: { user_id } }, res) => {
|
||||
try {
|
||||
const profile = await Profile.findOne({
|
||||
user: user_id
|
||||
}).populate('user', ['name', 'avatar']);
|
||||
user: user_id,
|
||||
}).populate("user", ["name", "avatar"]);
|
||||
|
||||
if (!profile) return res.status(400).json({ msg: 'Profile not found' });
|
||||
if (!profile) return res.status(400).json({ msg: "Profile not found" });
|
||||
|
||||
return res.json(profile);
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ msg: 'Server error' });
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
return res.status(500).json({ msg: "Server error" });
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// @route DELETE api/profile
|
||||
// @desc Delete profile, user & posts
|
||||
// @access Private
|
||||
router.delete('/', auth, async (req, res) => {
|
||||
router.delete("/", auth, async (req, res) => {
|
||||
try {
|
||||
// Remove user posts
|
||||
// Remove profile
|
||||
@@ -163,16 +163,14 @@ router.delete('/', auth, async (req, res) => {
|
||||
await Promise.all([
|
||||
Post.deleteMany({ user: req.user.id }),
|
||||
Profile.findOneAndRemove({ user: req.user.id }),
|
||||
User.findOneAndRemove({ _id: req.user.id })
|
||||
User.findOneAndRemove({ _id: req.user.id }),
|
||||
]);
|
||||
|
||||
res.json({ msg: 'User deleted' });
|
||||
res.json({ msg: "User deleted" });
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
res.status(500).send("Server Error");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -180,11 +178,11 @@ router.delete('/', auth, async (req, res) => {
|
||||
// @desc Add profile experience
|
||||
// @access Private
|
||||
router.put(
|
||||
'/experience',
|
||||
"/experience",
|
||||
auth,
|
||||
check('title', 'Title is required').notEmpty(),
|
||||
check('company', 'Company is required').notEmpty(),
|
||||
check('from', 'From date is required and needs to be from the past')
|
||||
check("title", "Title is required").notEmpty(),
|
||||
check("company", "Company is required").notEmpty(),
|
||||
check("from", "From date is required and needs to be from the past")
|
||||
.notEmpty()
|
||||
.custom((value, { req }) => (req.body.to ? value < req.body.to : true)),
|
||||
async (req, res) => {
|
||||
@@ -205,26 +203,24 @@ router.put(
|
||||
res.json(profile);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
res.status(500).send("Server Error");
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// @route DELETE api/profile/experience/:exp_id
|
||||
// @desc Delete experience from profile
|
||||
// @access Private
|
||||
|
||||
router.delete('/experience/:exp_id', auth, async (req, res) => {
|
||||
router.delete("/experience/:exp_id", auth, async (req, res) => {
|
||||
try {
|
||||
if (isUserId(req)) {
|
||||
const foundProfile = await Profile.findOne({ user: req.user.id });
|
||||
if (foundProfile) {
|
||||
foundProfile.experience = foundProfile.experience.filter(
|
||||
(exp: any) => exp._id.toString() !== req.params.exp_id
|
||||
(exp: any) => exp._id.toString() !== req.params.exp_id,
|
||||
);
|
||||
|
||||
await foundProfile.save();
|
||||
@@ -232,11 +228,9 @@ router.delete('/experience/:exp_id', auth, async (req, res) => {
|
||||
return res.status(200).json(foundProfile);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ msg: 'Server error' });
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
return res.status(500).json({ msg: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -244,12 +238,12 @@ router.delete('/experience/:exp_id', auth, async (req, res) => {
|
||||
// @desc Add profile education
|
||||
// @access Private
|
||||
router.put(
|
||||
'/education',
|
||||
"/education",
|
||||
auth,
|
||||
check('school', 'School is required').notEmpty(),
|
||||
check('degree', 'Degree is required').notEmpty(),
|
||||
check('fieldofstudy', 'Field of study is required').notEmpty(),
|
||||
check('from', 'From date is required and needs to be from the past')
|
||||
check("school", "School is required").notEmpty(),
|
||||
check("degree", "Degree is required").notEmpty(),
|
||||
check("fieldofstudy", "Field of study is required").notEmpty(),
|
||||
check("from", "From date is required and needs to be from the past")
|
||||
.notEmpty()
|
||||
.custom((value, { req }) => (req.body.to ? value < req.body.to : true)),
|
||||
async (req, res) => {
|
||||
@@ -269,62 +263,58 @@ router.put(
|
||||
res.json(profile);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
res.status(500).send('Server Error');
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
res.status(500).send("Server Error");
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// @route DELETE api/profile/education/:edu_id
|
||||
// @desc Delete education from profile
|
||||
// @access Private
|
||||
|
||||
router.delete('/education/:edu_id', auth, async (req, res) => {
|
||||
router.delete("/education/:edu_id", auth, async (req, res) => {
|
||||
try {
|
||||
if (isUserId(req)) {
|
||||
const foundProfile = await Profile.findOne({ user: req.user.id });
|
||||
if (foundProfile) {
|
||||
foundProfile.education = foundProfile.education.filter(
|
||||
(edu: any) => edu._id.toString() !== req.params.edu_id
|
||||
(edu: any) => edu._id.toString() !== req.params.edu_id,
|
||||
);
|
||||
await foundProfile.save();
|
||||
}
|
||||
return res.status(200).json(foundProfile);
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ msg: 'Server error' });
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
return res.status(500).json({ msg: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// @route GET api/profile/github/:username
|
||||
// @desc Get user repos from Github
|
||||
// @access Public
|
||||
router.get('/github/:username', async (req, res) => {
|
||||
router.get("/github/:username", async (req, res) => {
|
||||
console.log(config.get("githubToken"));
|
||||
console.log(req.params.username);
|
||||
try {
|
||||
const uri = encodeURI(
|
||||
`https://api.github.com/users/${req.params.username}/repos?per_page=5&sort=created:asc`
|
||||
`https://api.github.com/users/${req.params.username}/repos?per_page=5&sort=created:asc`,
|
||||
);
|
||||
const headers = {
|
||||
'user-agent': 'node.js',
|
||||
Authorization: `token ${config.get('githubToken')}`
|
||||
"user-agent": "node.js",
|
||||
Authorization: `token ${config.get("githubToken")}`,
|
||||
};
|
||||
|
||||
const gitHubResponse = await axios.get(uri, { headers });
|
||||
return res.json(gitHubResponse.data);
|
||||
} catch (err: unknown) {
|
||||
if (typeof err === 'string')
|
||||
console.error(err)
|
||||
else if (err instanceof Error)
|
||||
console.error(err.message);
|
||||
return res.status(404).json({ msg: 'No Github profile found' });
|
||||
if (typeof err === "string") console.error(err);
|
||||
else if (err instanceof Error) console.error(err.message);
|
||||
return res.status(404).json({ msg: "No Github profile found" });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user