Skip to content

Commit 89036d2

Browse files
Ravi Mauryashahparth36atharvapatil123
authored
Interview Experience Feature (#204)
* interviewExp init * Barebones working of write exp page * test changes * Added Company and Interview model * Added company crud apis * added basic interview apis * Experience Feature UI * Slight changes on Experience card * Add company + image upload in exp * Verify experiences * Read experience added * SLight changes * added cache and auth middleware * Added button for My Experiences * Added My Experiences page * removed comments from controller * removed next from parameter * Add Company page button * Draft button and Delete company added * Delete, Update company features added * working build with Alert messages & auth * style extension + page authorization * creating card components Co-authored-by: shahparth36 <parthshah1936@gmail.com> Co-authored-by: Atharva Patil <atharva7275@gmail.com>
1 parent b2278ab commit 89036d2

25 files changed

+3034
-78
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/node_modules
55
/.pnp
66
.pnp.js
7-
7+
/package-lock.json
88
# testing
99
/coverage
1010

new_client/package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
"private": true,
55
"dependencies": {
66
"@date-io/date-fns": "1.3.13",
7+
"@editorjs/code": "^2.7.0",
8+
"@editorjs/editorjs": "^2.23.2",
9+
"@editorjs/header": "^2.6.2",
10+
"@editorjs/image": "^2.6.2",
11+
"@editorjs/link": "^2.4.0",
12+
"@editorjs/list": "^1.7.0",
13+
"@editorjs/raw": "^2.3.0",
14+
"@editorjs/table": "^2.0.1",
715
"@material-ui/core": "^4.9.10",
816
"@material-ui/icons": "^4.9.1",
917
"@material-ui/lab": "^4.0.0-alpha.56",
@@ -17,6 +25,7 @@
1725
"bootstrap": "^4.4.1",
1826
"clsx": "^1.1.1",
1927
"date-fns": "^2.15.0",
28+
"editorjs-style": "^3.0.2",
2029
"jwt-decode": "^3.1.2",
2130
"react": "^16.13.1",
2231
"react-bootstrap": "^1.0.1",
@@ -78,4 +87,4 @@
7887
"prettier": "2.2.1",
7988
"sass": "^1.49.7"
8089
}
81-
}
90+
}

new_client/src/App.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,35 @@ const LazyAddMagazine = lazy(() =>
5454
import("./components/magazines/AddMagazine")
5555
);
5656

57+
// Experiences
58+
const LazyWriteExperience = lazy(() =>
59+
import("./components/experiences/WriteExperience")
60+
);
61+
const LazyCompanyList = lazy(() =>
62+
import("./components/experiences/CompanyList")
63+
);
64+
const LazyExperienceList = lazy(() =>
65+
import("./components/experiences/ExperienceList")
66+
);
67+
const LazyManageCompanies = lazy(() =>
68+
import("./components/experiences/ManageCompanies")
69+
);
70+
const LazyAddCompany = lazy(() =>
71+
import("./components/experiences/AddCompany")
72+
);
73+
const LazyManageExperiences = lazy(() =>
74+
import("./components/experiences/ManageExperiences")
75+
);
76+
const LazyVerifyExperience = lazy(() =>
77+
import("./components/experiences/VerifyExperience")
78+
);
79+
const LazyReadExperience = lazy(() =>
80+
import("./components/experiences/ReadExperience")
81+
);
82+
const LazyMyExperiences = lazy(() =>
83+
import("./components/experiences/MyExperiences")
84+
);
85+
5786
const theme = responsiveFontSizes(createMuiTheme());
5887
const Lazy404 = lazy(() => import("./components/404/NotFound"));
5988

@@ -137,6 +166,18 @@ function App() {
137166
path="/magazine/edit/:id"
138167
component={LazyAddMagazine}
139168
/>
169+
170+
<ProtectedRoute path="/writeexp" component={LazyWriteExperience} />
171+
<Route path="/exp/list/:id" component={LazyExperienceList} />
172+
<Route path="/exp/edit/:id" component={LazyWriteExperience} />
173+
<Route path="/exp/:id" component={LazyReadExperience} />
174+
<Route path="/exp" component={LazyCompanyList} />
175+
<ProtectedRoute path="/myexp" component={LazyMyExperiences} />
176+
<ProtectedRoute path="/managecompanies" component={LazyManageCompanies} />
177+
<ProtectedRoute path="/addcompany" component={LazyAddCompany} />
178+
<ProtectedRoute path="/manageexperiences" component={LazyManageExperiences} />
179+
<ProtectedRoute path="/verifyexperience/:id" component={LazyVerifyExperience} />
180+
140181
<Route component={Lazy404} />
141182
</Switch>
142183
</Suspense>

new_client/src/components/Header.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ function Header(props) {
121121
>
122122
<nav className={getNavItemContClass("alumni")}>ALUMNI</nav>
123123
</Link>
124+
<Link
125+
to="/exp"
126+
className={navItemClass}
127+
onClick={() => currPageChange("exp")}
128+
>
129+
<nav className={getNavItemContClass("exp")}>EXPERIENCES</nav>
130+
</Link>
124131
{/* <Link
125132
to="/blogs"
126133
className={navItemClass}

new_client/src/components/Utilities/Banner.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)),
5858
url("../assets/magazines.webp");
5959
min-height: 100vh;
60+
} @else if $page == "Experience" {
61+
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)),
62+
url("../assets/experience.webp");
63+
min-height: 100vh;
6064
}
6165
}
6266

@@ -83,6 +87,7 @@
8387
top: 70%;
8488
left: 50%;
8589
transform: translate(-50%, -50%);
90+
display: flex;
8691
}
8792

8893
@media only screen and (max-width: 600px) {
@@ -113,3 +118,6 @@ section.projectsBanner {
113118
section.magazinesBanner {
114119
@include Banner("Magazines");
115120
}
121+
section.experienceBanner {
122+
@include Banner("Experience");
123+
}
4.16 KB
Loading
162 KB
Loading

new_client/src/components/events/IndividualEvent.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export default function IndividualEvent({
9090
disableSpacing="true"
9191
style={{ display: "flex", justifyContent: "space-between" }}
9292
>
93-
{isMember && (
93+
{/* {isMember && ( */}
9494
<>
9595
<Link to={`event/edit/${article._id}`}>
9696
<IconButton>
@@ -101,7 +101,7 @@ export default function IndividualEvent({
101101
<DeleteOutlinedIcon style={{ color: red[400] }} />
102102
</IconButton>
103103
</>
104-
)}
104+
{/* )} */}
105105
<Link to={`/events/${article._id}`}>
106106
<Button
107107
variant="contained"
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
import "date-fns";
2+
import React from "react";
3+
import axios from "axios";
4+
import Spinner from "../spinner/Spinner";
5+
import "../auth/Error.css";
6+
import { useState } from "react";
7+
import { Button, Grid, TextField } from "@material-ui/core";
8+
import DateFnsUtils from "@date-io/date-fns";
9+
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
10+
import { connect } from "react-redux";
11+
import AlertUtility from "../Utilities/Alert";
12+
import { useEffect } from "react";
13+
import { useLocation, withRouter } from "react-router-dom";
14+
import useAuthenticatedAxios from "../Utilities/useAuthenticatedAxios.js";
15+
16+
function AddCompany(props) {
17+
const authenticatedAxios = useAuthenticatedAxios();
18+
const [companyName, setCompanyName] = useState("");
19+
const [companySelectedFile, setCompanySelectedFile] = useState(null);
20+
21+
const [isError, setIsError] = useState(false);
22+
const [isSubmitted, setIsSubmitted] = useState(false);
23+
const [isLoading, setIsLoading] = useState(false);
24+
25+
const { pathname } = useLocation();
26+
const companyID = pathname.split("/")[3];
27+
const isCompanyPage = !!companyID;
28+
const successString = isCompanyPage
29+
? "Company edited successfully! "
30+
: "Company added successfully";
31+
const btnText = isCompanyPage ? "Update" : "Submit";
32+
33+
const [error, setError] = useState({
34+
companyNameError: "",
35+
fileError: "",
36+
});
37+
38+
useEffect(() => {
39+
if (isCompanyPage && companyID) {
40+
axios
41+
.get(process.env.REACT_APP_API + `/company/${companyID}`)
42+
.then((res) => {
43+
setCompanyName(res.data.companyName);
44+
setCompanySelectedFile(res.data.companySelectedFile);
45+
})
46+
.catch((err) => console.log(err));
47+
}
48+
}, [isCompanyPage, companyID]);
49+
50+
const handleClose = () => {
51+
setIsSubmitted(false);
52+
if (props.closeModal !== undefined) props.closeModal(); // EditPage is a page, so no modal
53+
props.history.push("/managecompanies");
54+
};
55+
56+
const isValid = () => {
57+
let ret = true;
58+
if (companyName === "") {
59+
setError((prevError) => ({
60+
...prevError,
61+
companyNameError: "*Company name cannot be empty",
62+
}));
63+
ret = false;
64+
}
65+
if (!companySelectedFile) {
66+
setError((prevError) => ({
67+
...prevError,
68+
fileError: "*Company image field cannot be empty",
69+
}));
70+
ret = false;
71+
}
72+
return ret;
73+
};
74+
75+
const onFileChange = (e) => {
76+
setCompanySelectedFile(e.target.files[0]);
77+
};
78+
79+
const handleAddCompany = (event) => {
80+
event.preventDefault();
81+
if (isValid()) {
82+
const formData = new FormData();
83+
const url = process.env.REACT_APP_API + "/company";
84+
if (companySelectedFile) {
85+
formData.append(
86+
"companyLogo",
87+
companySelectedFile,
88+
companySelectedFile.name
89+
);
90+
}
91+
formData.append("companyName", companyName);
92+
setIsLoading(true);
93+
authenticatedAxios
94+
.post(url, formData)
95+
.then((res) => {
96+
if (res.status === 200) {
97+
setIsSubmitted(true);
98+
} else {
99+
setIsError(true);
100+
}
101+
setIsLoading(false);
102+
})
103+
.catch((err) => {
104+
setIsError(true);
105+
setIsLoading(false);
106+
console.log(err);
107+
});
108+
}
109+
};
110+
111+
const handleEditCompany = (event) => {
112+
event.preventDefault();
113+
if (isValid()) {
114+
const formData = new FormData();
115+
const url = process.env.REACT_APP_API + `/company/${companyID}`;
116+
if (companySelectedFile) {
117+
formData.append(
118+
"companyLogo",
119+
companySelectedFile,
120+
companySelectedFile.name
121+
);
122+
}
123+
formData.append("companyName", companyName);
124+
setIsLoading(true);
125+
authenticatedAxios
126+
.put(url, formData)
127+
.then((res) => {
128+
if (res.status === 200) {
129+
setIsSubmitted(true);
130+
} else {
131+
setIsError(true);
132+
}
133+
setIsLoading(false);
134+
})
135+
.catch((err) => {
136+
setIsError(true);
137+
setIsLoading(false);
138+
console.log(err);
139+
});
140+
}
141+
};
142+
143+
return (
144+
<div>
145+
<MuiPickersUtilsProvider utils={DateFnsUtils}>
146+
<div className="jumbotron" style={{ margin: "20px 50px" }}>
147+
<form onSubmit={isCompanyPage ? handleEditCompany : handleAddCompany}>
148+
<div className="form-group">
149+
<Grid container>
150+
<Grid item xs={12}>
151+
<TextField
152+
placeholder="Company Name"
153+
name="companyName"
154+
value={companyName}
155+
onChange={(e) => setCompanyName(e.target.value)}
156+
required
157+
label="Enter Company Name"
158+
disabled={isCompanyPage}
159+
/>
160+
<div className="errorMsg">{error.companyNameError}</div>
161+
</Grid>
162+
</Grid>
163+
</div>
164+
<div className="form-group">
165+
<label>Company Logo:</label>
166+
<input
167+
type="file"
168+
className="btn"
169+
name="companyLogo"
170+
accept="image/*"
171+
onChange={onFileChange}
172+
/>
173+
<div className="errorMsg">{error.fileError}</div>
174+
</div>
175+
<Grid container spacing={1}>
176+
<Grid item>
177+
{isLoading ? (
178+
<Spinner />
179+
) : (
180+
<Button type="submit" variant="outlined" color="primary">
181+
{btnText}
182+
</Button>
183+
)}
184+
</Grid>
185+
<Grid item>
186+
{isCompanyPage && (
187+
<Button
188+
type="submit"
189+
variant="outlined"
190+
color="primary"
191+
className="btn btn-primary"
192+
onClick={() => props.history.goBack()}
193+
>
194+
Cancel
195+
</Button>
196+
)}
197+
</Grid>
198+
</Grid>
199+
</form>
200+
</div>
201+
</MuiPickersUtilsProvider>
202+
<AlertUtility
203+
open={isSubmitted}
204+
duration={3000}
205+
onCloseHandler={handleClose}
206+
severity="success"
207+
message={successString + " Reloading companies..."}
208+
/>
209+
<AlertUtility
210+
open={isError}
211+
duration={2000}
212+
onCloseHandler={() => {
213+
setIsError(false);
214+
}}
215+
severity="error"
216+
message="Oops! An error occurred. Please try again."
217+
/>
218+
</div>
219+
);
220+
}
221+
222+
const mapStateToProps = (state) => ({
223+
userID: state.auth.userID,
224+
token: state.auth.token,
225+
username: state.auth.username,
226+
});
227+
228+
export default withRouter(connect(mapStateToProps)(AddCompany));

0 commit comments

Comments
 (0)