├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── _redirects ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── readmeResources ├── aboutme.PNG ├── addEducation.PNG ├── adminDashboead.PNG ├── adminlogin.PNG ├── contact.PNG ├── contactAdmin.PNG ├── editEdication.PNG ├── education.PNG ├── educationAdmin.PNG ├── experience.PNG ├── experienceAdmin.PNG ├── footer.PNG ├── home.PNG ├── projectAdmin.PNG ├── projects.PNG ├── skills.PNG └── skilsAdmin.PNG └── src ├── App.js ├── actions ├── educationAction.js ├── experienceAction.js ├── loginAction.js ├── messageAction.js ├── projectAction.js └── skillAction.js ├── apis ├── educationApi.js ├── experienceApi.js ├── messageApi.js ├── projectApi.js ├── serverApi.js ├── skillApi.js └── userApi.js ├── assets └── images │ ├── basry-logo.png │ ├── dev.png │ ├── dev.svg │ ├── education.png │ ├── experience.png │ └── profil.png ├── components ├── Admin │ ├── EducationModal.js │ ├── ExperienceModal.js │ ├── Modal.js │ ├── ProjectModal.js │ ├── SideBar │ │ ├── SideBar.css │ │ ├── SideBar.js │ │ └── SidebarData.js │ ├── SkillModal.js │ └── Table.js └── User │ ├── About │ ├── About.css │ └── About.js │ ├── Contacts │ └── Contacts.js │ ├── Education │ └── Education.js │ ├── Experience │ └── Experience.js │ ├── Footer │ ├── Footer.css │ └── Footer.js │ ├── Login │ ├── Login.js │ └── styles.css │ ├── Navbar │ ├── Navbar.js │ └── styles.css │ ├── PageIntro │ ├── PageIntro.js │ └── styles.css │ ├── Projects │ └── Projects.js │ └── Skills │ └── Skills.js ├── index.css ├── index.js ├── pages ├── EducationAdmin.js ├── ExperienceAdmin.js ├── Home.js ├── MessageAdmin.js ├── NotFound.js ├── PortfolioUI.js ├── ProjectAdmin.js └── SkillAdmin.js ├── reducers ├── education.js ├── experience.js ├── index.js ├── isLogged.js ├── message.js ├── project.js └── skill.js ├── reportWebVitals.js └── shared ├── SecureRoute.js ├── authorization.js ├── history.js └── toast.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Basry Portfolio Frontend Part 2 | 3 | Dynamic personal website with admin panel which contains educations, experiences, skills, projects, contact fields. 4 | ## Technologies 5 | ##### MERN STACK: Mongo DB, ExpressJS, ReactJS, NodeJS. 6 | 7 | ## Dependancies 8 | * react 9 | * redux 10 | * react-redux 11 | * redux-thunk 12 | * react-router-dom 13 | * react-hook-form 14 | * axios 15 | * moment 16 | * react-datepicker 17 | * react-dom 18 | * react-icons 19 | * react-modal-image 20 | * react-scripts 21 | * react-skillbars 22 | * react-toastify 23 | * web-vitals 24 | 25 | 26 | ## Project Screen Shots 27 | ### Intro 28 | ![Home page](readmeResources/home.PNG) 29 | ### About Me 30 | ![About Me](readmeResources/aboutme.PNG) 31 | ### Educations 32 | ![Education](readmeResources/education.PNG) 33 | ### Experiences 34 | ![Experience](readmeResources/experience.PNG) 35 | ### Skills 36 | ![Skills](readmeResources/skills.PNG) 37 | ### Projects 38 | ![Projects](readmeResources/projects.PNG) 39 | ### Contact Me 40 | ![Contact](readmeResources/contact.PNG) 41 | ### Footer 42 | ![Footer](readmeResources/footer.PNG) 43 | ### Login Admin Page 44 | ![Login](readmeResources/adminlogin.PNG) 45 | ### Dashboard Admin 46 | ![Dashboard](readmeResources/adminDashboead.PNG) 47 | ### Educations Admin 48 | ![Educations Admin](readmeResources/educationAdmin.PNG) 49 | ### Add Education 50 | ![Add Education](readmeResources/addEducation.PNG) 51 | ### Edit Education 52 | ![Edit Education](readmeResources/editEdication.PNG) 53 | ### Experiences Admin 54 | ![Experiences Admin](readmeResources/experienceAdmin.PNG) 55 | ### Skills Admin 56 | ![Skills Admin](readmeResources/skilsAdmin.PNG) 57 | ### Project Admin 58 | ![Project Admin](readmeResources/projectAdmin.PNG) 59 | ### Contact Admin 60 | ![Contact Admin](readmeResources/contactAdmin.PNG) 61 | 62 | 63 | ## Demo 64 | Click [Demo](https://basry.herokuapp.com/) to go to the demonstration page. 65 | 66 | ## Installation and Setup Instructions 67 | 68 | Clone down this repository. You will need `node` and `npm` installed globally on your machine. 69 | 70 | Installation: 71 | 72 | `npm install` 73 | 74 | 75 | To Start Server: 76 | 77 | `npm start` 78 | 79 | To Visit App: 80 | 81 | `localhost:3000/` 82 | 83 | ## Notes 84 | * please note that the application will not work before colone the API express, click [here](https://github.com/oussamabasry/portfolio-backend) to go to backend repository. 85 | * Change the server IP address in /src/app/serverApi.js file. 86 | 87 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "portfolio-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.12.0", 7 | "@testing-library/react": "^11.2.6", 8 | "@testing-library/user-event": "^12.8.3", 9 | "axios": "^0.21.1", 10 | "jquery": "^3.6.0", 11 | "moment": "^2.29.1", 12 | "react": "^17.0.2", 13 | "react-datepicker": "^3.8.0", 14 | "react-dom": "^17.0.2", 15 | "react-hook-form": "^7.3.6", 16 | "react-icons": "^4.2.0", 17 | "react-modal-image": "^2.5.0", 18 | "react-redux": "^7.2.4", 19 | "react-router-dom": "^5.2.0", 20 | "react-scripts": "4.0.3", 21 | "react-skillbars": "^1.6.1", 22 | "react-toastify": "^7.0.4", 23 | "redux": "^4.1.0", 24 | "redux-thunk": "^2.3.0", 25 | "web-vitals": "^1.1.1" 26 | }, 27 | "scripts": { 28 | "start": "react-scripts start", 29 | "build": "react-scripts build", 30 | "test": "react-scripts test", 31 | "eject": "react-scripts eject" 32 | }, 33 | "eslintConfig": { 34 | "extends": [ 35 | "react-app", 36 | "react-app/jest" 37 | ] 38 | }, 39 | "browserslist": { 40 | "production": [ 41 | ">0.2%", 42 | "not dead", 43 | "not op_mini all" 44 | ], 45 | "development": [ 46 | "last 1 chrome version", 47 | "last 1 firefox version", 48 | "last 1 safari version" 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | 28 | 29 | 33 | 34 | 38 | 39 | 45 | Basry 46 | 47 | 48 | 49 |
50 | 60 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /readmeResources/aboutme.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/aboutme.PNG -------------------------------------------------------------------------------- /readmeResources/addEducation.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/addEducation.PNG -------------------------------------------------------------------------------- /readmeResources/adminDashboead.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/adminDashboead.PNG -------------------------------------------------------------------------------- /readmeResources/adminlogin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/adminlogin.PNG -------------------------------------------------------------------------------- /readmeResources/contact.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/contact.PNG -------------------------------------------------------------------------------- /readmeResources/contactAdmin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/contactAdmin.PNG -------------------------------------------------------------------------------- /readmeResources/editEdication.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/editEdication.PNG -------------------------------------------------------------------------------- /readmeResources/education.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/education.PNG -------------------------------------------------------------------------------- /readmeResources/educationAdmin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/educationAdmin.PNG -------------------------------------------------------------------------------- /readmeResources/experience.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/experience.PNG -------------------------------------------------------------------------------- /readmeResources/experienceAdmin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/experienceAdmin.PNG -------------------------------------------------------------------------------- /readmeResources/footer.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/footer.PNG -------------------------------------------------------------------------------- /readmeResources/home.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/home.PNG -------------------------------------------------------------------------------- /readmeResources/projectAdmin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/projectAdmin.PNG -------------------------------------------------------------------------------- /readmeResources/projects.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/projects.PNG -------------------------------------------------------------------------------- /readmeResources/skills.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/skills.PNG -------------------------------------------------------------------------------- /readmeResources/skilsAdmin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/readmeResources/skilsAdmin.PNG -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Router, Route, Switch } from "react-router-dom"; 3 | import { useSelector } from "react-redux"; 4 | import PortfolioUI from "./pages/PortfolioUI"; 5 | import Login from "./components/User/Login/Login"; 6 | import SideBar from "./components/Admin/SideBar/SideBar"; 7 | import EducationAdmin from "./pages/EducationAdmin"; 8 | import { ToastContainer } from "react-toastify"; 9 | import history from "./shared/history"; 10 | import SecureRoute from "./shared/SecureRoute"; 11 | import ExperienceAdmin from "./pages/ExperienceAdmin"; 12 | import SkillAdmin from "./pages/SkillAdmin"; 13 | import MessageAdmin from "./pages/MessageAdmin"; 14 | import isLogin from "./shared/authorization"; 15 | import ProjectAdmin from "./pages/ProjectAdmin"; 16 | import NotFound from "./pages/NotFound"; 17 | 18 | function App() { 19 | const [isLogged, setIsLogged] = useState(isLogin); 20 | const login = useSelector((state) => state.login.isLogin); 21 | 22 | useEffect(() => { 23 | setIsLogged(isLogin); 24 | }, [login]); 25 | 26 | return ( 27 |
28 | 29 | {isLogged && } 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 52 |
53 | ); 54 | } 55 | 56 | export default App; 57 | -------------------------------------------------------------------------------- /src/actions/educationAction.js: -------------------------------------------------------------------------------- 1 | import { 2 | addEducationApi, 3 | getEducationsApi, 4 | deleteEducationApi, 5 | updateEducationApi, 6 | } from "../apis/educationApi"; 7 | import { toastSuccess, toastError } from "../shared/toast"; 8 | 9 | export const getEducations = () => async (dispatch) => { 10 | try { 11 | const { data } = await getEducationsApi(); 12 | dispatch({ type: "GET_EDUCATIONS", payload: data }); 13 | } catch (error) { 14 | console.log(error); 15 | } 16 | }; 17 | 18 | export const addEducation = (education) => async (dispatch) => { 19 | try { 20 | const { data } = await addEducationApi(education); 21 | dispatch({ type: "ADD_EDUCATION", payload: data }); 22 | toastSuccess("Education Added Successfully"); 23 | } catch (error) { 24 | console.log(error); 25 | toastError("Error while adding education"); 26 | } 27 | }; 28 | 29 | export const deleteEducation = (id) => async (dispatch) => { 30 | try { 31 | await deleteEducationApi(id); 32 | toastSuccess("Education Deleted Successfully"); 33 | dispatch({ type: "DELETE_EDUCATION", payload: id }); 34 | } catch (error) { 35 | console.log(error); 36 | toastError("Error while deleting education"); 37 | } 38 | }; 39 | 40 | export const updateEducation = (id, education) => async (dispatch) => { 41 | try { 42 | const { data } = await updateEducationApi(id, education); 43 | dispatch({ 44 | type: "UPDATE_EDUCATION", 45 | payload: {...education,_id: data.education._id} 46 | }); 47 | toastSuccess("Education Updated Successfully"); 48 | } catch (error) { 49 | console.log(error); 50 | toastError("Error while Updated education"); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /src/actions/experienceAction.js: -------------------------------------------------------------------------------- 1 | import { 2 | addExperienceApi, 3 | getExperiencesApi, 4 | deleteExperienceApi, 5 | updateExperienceApi, 6 | } from "../apis/experienceApi"; 7 | import { toastSuccess, toastError } from "../shared/toast"; 8 | 9 | export const getExperiences = () => async (dispatch) => { 10 | try { 11 | const { data } = await getExperiencesApi(); 12 | dispatch({ type: "GET_EXPERIENCES", payload: data }); 13 | } catch (error) { 14 | console.log(error); 15 | } 16 | }; 17 | 18 | export const addExperience = (experience) => async (dispatch) => { 19 | try { 20 | const { data } = await addExperienceApi(experience); 21 | dispatch({ type: "ADD_EXEPERIENCE", payload: data }); 22 | toastSuccess("Experience Added Successfully"); 23 | } catch (error) { 24 | console.log(error); 25 | toastError("Error while adding experience"); 26 | } 27 | }; 28 | 29 | export const deleteExperience = (id) => async (dispatch) => { 30 | try { 31 | await deleteExperienceApi(id); 32 | dispatch({ type: "DELETE_EXEPERIENCE", payload: id }); 33 | toastSuccess("Experience deleted Successfully"); 34 | } catch (error) { 35 | console.log(error); 36 | toastError("Error while deleting experience"); 37 | } 38 | }; 39 | 40 | export const updateExperience = (id, experience) => async (dispatch) => { 41 | try { 42 | const { data } = await updateExperienceApi(id, experience); 43 | dispatch({ 44 | type: "UPDATE_EXEPERIENCE", 45 | payload:{...experience,_id: data.experience._id}, 46 | }); 47 | toastSuccess("Experience Updated Successfully"); 48 | } catch (error) { 49 | console.log(error); 50 | toastError("Error while updating experience"); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /src/actions/loginAction.js: -------------------------------------------------------------------------------- 1 | import { loginApi } from "../apis/userApi"; 2 | import { toastSuccess, toastError } from "../shared/toast"; 3 | import history from "../shared/history"; 4 | import api from "../apis/serverApi"; 5 | 6 | export const loginUser = (authData) => async (dispatch) => { 7 | try { 8 | const { data } = await loginApi(authData); 9 | api.defaults.headers.common["Authorization"] = `Bearer ${data.token}`; 10 | localStorage.setItem( 11 | "userData", 12 | JSON.stringify({ 13 | token: data.token, 14 | isLogged: true, 15 | }) 16 | ); 17 | toastSuccess("Login Successfully"); 18 | dispatch({ 19 | type: "SIGN_IN", 20 | payload: { isLogin: true, token: data.token }, 21 | }); 22 | history.push("/education"); 23 | } catch (error) { 24 | console.log(error); 25 | toastError("Incorrect email or password"); 26 | } 27 | }; 28 | 29 | export const logoutUser = () => { 30 | delete api.defaults.headers.common["Authorization"]; 31 | localStorage.setItem( 32 | "userData", 33 | JSON.stringify({ 34 | token: null, 35 | isLogged: false, 36 | }) 37 | ); 38 | return { 39 | type: "LOGOUT", 40 | payload: { isLogin: false, token: null }, 41 | }; 42 | }; 43 | -------------------------------------------------------------------------------- /src/actions/messageAction.js: -------------------------------------------------------------------------------- 1 | import { getMessagesApi, updateMessageApi } from "../apis/messageApi"; 2 | 3 | export const getMessages = () => async (dispatch) => { 4 | try { 5 | const { data } = await getMessagesApi(); 6 | dispatch({ type: "GET_MESSAGES", payload: data }); 7 | } catch (error) { 8 | console.log(error); 9 | } 10 | }; 11 | 12 | export const updateMessage = (id, message) => async (dispatch) => { 13 | try { 14 | const { data } = await updateMessageApi(id, message); 15 | dispatch({ 16 | type: "UPDATE_MESSAGE", 17 | payload: { ...message, _id: data.message._id }, 18 | }); 19 | } catch (error) { 20 | console.log(error); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/actions/projectAction.js: -------------------------------------------------------------------------------- 1 | import { 2 | addProjectApi, 3 | getProjectsApi, 4 | deleteProjectApi, 5 | updateProjectApi, 6 | } from "../apis/projectApi"; 7 | import { toastSuccess, toastError } from "../shared/toast"; 8 | 9 | export const getprojects = () => async (dispatch) => { 10 | try { 11 | const { data } = await getProjectsApi(); 12 | dispatch({ type: "GET_PROJECTS", payload: data }); 13 | } catch (error) { 14 | console.log(error); 15 | } 16 | }; 17 | 18 | export const addProject = (project) => async (dispatch) => { 19 | try { 20 | const { data } = await addProjectApi(project); 21 | dispatch({ type: "ADD_PROJECT", payload: data }); 22 | toastSuccess("Project Added Successfully"); 23 | } catch (error) { 24 | console.log(error); 25 | toastError("Error while adding project"); 26 | } 27 | }; 28 | 29 | export const deleteProject = (id) => async (dispatch) => { 30 | try { 31 | await deleteProjectApi(id); 32 | dispatch({ type: "DELETE_PROJECT", payload: id }); 33 | toastSuccess("Project deleted Successfully"); 34 | } catch (error) { 35 | console.log(error); 36 | toastError("Error while deleting project"); 37 | } 38 | }; 39 | 40 | export const updateProject = (id, project) => async (dispatch) => { 41 | try { 42 | const { data } = await updateProjectApi(id, project); 43 | dispatch({ 44 | type: "UPDATE_PROJECT", 45 | payload: data.project, 46 | //payload:{...project,_id: data.project._id}, 47 | }); 48 | toastSuccess("Project Updated Successfully"); 49 | } catch (error) { 50 | console.log(error); 51 | toastError("Error while updating project"); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /src/actions/skillAction.js: -------------------------------------------------------------------------------- 1 | import { 2 | addSkillApi, 3 | getSkillsApi, 4 | deleteSkillApi, 5 | updateSkillApi, 6 | } from "../apis/skillApi"; 7 | import { toastSuccess, toastError } from "../shared/toast"; 8 | 9 | export const getSkills = () => async (dispatch) => { 10 | try { 11 | const { data } = await getSkillsApi(); 12 | dispatch({ type: "GET_SKILLS", payload: data }); 13 | } catch (error) { 14 | console.log(error); 15 | } 16 | }; 17 | 18 | export const addSkill = (skill) => async (dispatch) => { 19 | try { 20 | const { data } = await addSkillApi(skill); 21 | dispatch({ type: "ADD_SKILL", payload: data }); 22 | toastSuccess("Skill Added Successfully"); 23 | } catch (error) { 24 | console.log(error); 25 | toastError("Error while adding Skill"); 26 | } 27 | }; 28 | 29 | export const deleteSkill = (id) => async (dispatch) => { 30 | try { 31 | await deleteSkillApi(id); 32 | dispatch({ type: "DELETE_SKILL", payload: id }); 33 | toastSuccess("Skill deleted successfully"); 34 | } catch (error) { 35 | console.log(error); 36 | toastError("Error while deleting Skill"); 37 | } 38 | }; 39 | 40 | export const updateSkill = (id, skill) => async (dispatch) => { 41 | try { 42 | const { data } = await updateSkillApi(id, skill); 43 | dispatch({ 44 | type: "UPDATE_SKILL", 45 | payload: { ...skill, _id: data.skill._id }, 46 | }); 47 | toastSuccess("Skill updated successfully"); 48 | } catch (error) { 49 | console.log(error); 50 | toastError("Error while updating Skill"); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /src/apis/educationApi.js: -------------------------------------------------------------------------------- 1 | import api from "./serverApi"; 2 | 3 | export const addEducationApi = (education) => { 4 | return api.post("/educations/", education); 5 | }; 6 | 7 | export const getEducationsApi = () => { 8 | return api.get("/educations/"); 9 | }; 10 | 11 | export const deleteEducationApi = (educationId) => { 12 | return api.delete(`/educations/${educationId}`); 13 | }; 14 | 15 | export const updateEducationApi = (educationId, education) => { 16 | return api.put(`/educations/${educationId}`, education); 17 | }; 18 | -------------------------------------------------------------------------------- /src/apis/experienceApi.js: -------------------------------------------------------------------------------- 1 | import api from "./serverApi"; 2 | 3 | export const addExperienceApi = (experience) => { 4 | return api.post("/experiences/", experience); 5 | }; 6 | 7 | export const getExperiencesApi = () => { 8 | return api.get("/experiences/"); 9 | }; 10 | 11 | export const deleteExperienceApi = (experienceId) => { 12 | return api.delete(`/experiences/${experienceId}`); 13 | }; 14 | 15 | export const updateExperienceApi = (experienceId, experience) => { 16 | return api.put(`/experiences/${experienceId}`, experience); 17 | }; 18 | -------------------------------------------------------------------------------- /src/apis/messageApi.js: -------------------------------------------------------------------------------- 1 | import api from "./serverApi"; 2 | 3 | export const getMessagesApi = () => { 4 | return api.get("/messages/", { 5 | headers: { 6 | Authorization: `Bearer ${ 7 | JSON.parse(localStorage.getItem("userData")).token 8 | }`, 9 | }, 10 | }); 11 | }; 12 | 13 | export const updateMessageApi = (messageId, message) => { 14 | return api.put(`/messages/${messageId}`, message); 15 | }; 16 | -------------------------------------------------------------------------------- /src/apis/projectApi.js: -------------------------------------------------------------------------------- 1 | import api from "./serverApi"; 2 | 3 | export const addProjectApi = (project) => { 4 | return api.post("/projects/", project); 5 | }; 6 | 7 | export const getProjectsApi = () => { 8 | return api.get("/projects/"); 9 | }; 10 | 11 | export const deleteProjectApi = (projectId) => { 12 | return api.delete(`/projects/${projectId}`); 13 | }; 14 | 15 | export const updateProjectApi = (projectId, project) => { 16 | return api.put(`/projects/${projectId}`, project); 17 | }; 18 | -------------------------------------------------------------------------------- /src/apis/serverApi.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const api = axios.create({ 4 | baseURL: "https://basryback.herokuapp.com", 5 | }); 6 | 7 | export const setAuthorizationToken = (token) => { 8 | if (token) { 9 | axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; 10 | } else { 11 | delete axios.defaults.headers.common["Authorization"]; 12 | } 13 | }; 14 | 15 | export default api; 16 | 17 | export const domainName= "https://basryback.herokuapp.com/"; 18 | -------------------------------------------------------------------------------- /src/apis/skillApi.js: -------------------------------------------------------------------------------- 1 | import api from "./serverApi"; 2 | 3 | export const addSkillApi = (skill) => { 4 | return api.post("/skills/", skill); 5 | }; 6 | 7 | export const getSkillsApi = () => { 8 | return api.get("/skills/"); 9 | }; 10 | 11 | export const deleteSkillApi = (skillId) => { 12 | return api.delete(`/skills/${skillId}`); 13 | }; 14 | 15 | export const updateSkillApi = (skillId, skill) => { 16 | return api.put(`/skills/${skillId}`, skill); 17 | }; 18 | -------------------------------------------------------------------------------- /src/apis/userApi.js: -------------------------------------------------------------------------------- 1 | import api from "./serverApi"; 2 | 3 | export const loginApi = (authData) => { 4 | return api.post("/users/login", authData); 5 | }; 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/images/basry-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/src/assets/images/basry-logo.png -------------------------------------------------------------------------------- /src/assets/images/dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/src/assets/images/dev.png -------------------------------------------------------------------------------- /src/assets/images/dev.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 665 | -------------------------------------------------------------------------------- /src/assets/images/education.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/src/assets/images/education.png -------------------------------------------------------------------------------- /src/assets/images/experience.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/src/assets/images/experience.png -------------------------------------------------------------------------------- /src/assets/images/profil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oussamabasry/portfolio-frontend-react/f20796f0cb938cce010cb3a83eb2f75c08139bd0/src/assets/images/profil.png -------------------------------------------------------------------------------- /src/components/Admin/EducationModal.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useForm } from "react-hook-form"; 3 | import { useDispatch } from "react-redux"; 4 | import { addEducation, updateEducation } from "../../actions/educationAction"; 5 | import DatePicker from "react-datepicker"; 6 | import "react-datepicker/dist/react-datepicker.css"; 7 | 8 | const EducationModal = ({ id, header, edu, submitValue, colorButton }) => { 9 | const [startDate, setStartDate] = useState(new Date()); 10 | const [endDate, setEndDate] = useState(new Date()); 11 | const { register, handleSubmit, reset, setValue } = useForm(); 12 | const dispatch = useDispatch(); 13 | 14 | useEffect(() => { 15 | if (id === "editEducation") { 16 | setValue("title", edu.title); 17 | setValue("school", edu.school); 18 | setValue("city", edu.city); 19 | setStartDate(Date.parse(edu.startDate)); 20 | setStartDate(Date.parse(edu.endDate)); 21 | } 22 | }, [edu, id, setValue]); 23 | 24 | const onClick = (data) => { 25 | data.startDate = startDate; 26 | data.endDate = endDate; 27 | if (id === "editEducation") { 28 | dispatch(updateEducation(edu._id, data)); 29 | } else { 30 | dispatch(addEducation(data)); 31 | } 32 | reset(); 33 | }; 34 | return ( 35 |
36 | 153 |
154 | ); 155 | }; 156 | 157 | export default EducationModal; 158 | -------------------------------------------------------------------------------- /src/components/Admin/ExperienceModal.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useForm } from "react-hook-form"; 3 | import { useDispatch } from "react-redux"; 4 | import { 5 | addExperience, 6 | updateExperience, 7 | } from "../../actions/experienceAction"; 8 | import DatePicker from "react-datepicker"; 9 | import "react-datepicker/dist/react-datepicker.css"; 10 | 11 | const ExperienceModal = ({ id, header, exp, submitValue, colorButton }) => { 12 | const [startDate, setStartDate] = useState(new Date()); 13 | const [endDate, setEndDate] = useState(new Date()); 14 | const { register, handleSubmit, reset, setValue } = useForm(); 15 | const dispatch = useDispatch(); 16 | 17 | useEffect(() => { 18 | if (id === "editExperience") { 19 | setValue("title", exp.title); 20 | setValue("company", exp.company); 21 | setValue("city", exp.city); 22 | setStartDate(Date.parse(exp.startDate)); 23 | setEndDate(Date.parse(exp.endDate)); 24 | setValue("description", exp.description); 25 | setValue("technologies", exp.technologies); 26 | } 27 | }, [exp, id, setValue]); 28 | 29 | const onClick = (data) => { 30 | data.startDate = startDate; 31 | data.endDate = endDate; 32 | if (id === "editExperience") { 33 | dispatch(updateExperience(exp._id, data)); 34 | } else { 35 | dispatch(addExperience(data)); 36 | } 37 | reset(); 38 | }; 39 | return ( 40 |
41 |