From 4a400da35d33faa087a9c73d8536283985ac4ed3 Mon Sep 17 00:00:00 2001 From: manish Date: Fri, 3 Nov 2023 18:10:39 +0530 Subject: [PATCH 1/2] some changes are login and signup page and sidebar --- frontend/package-lock.json | 1 - frontend/src/components/slider/Sidenav.tsx | 23 ++- frontend/src/pages/Templates/Form.tsx | 1 - frontend/src/pages/auth/Login.tsx | 62 +++--- frontend/src/pages/auth/Register.tsx | 66 ++++--- frontend/src/redux/api/jobApi.ts | 14 +- frontend/src/redux/features/menuSlice.ts | 10 +- frontend/src/types/api.types.ts | 213 +++++++++++++++------ 8 files changed, 258 insertions(+), 132 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 036d7a0..a444762 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,6 @@ "name": "frontend", "version": "0.0.0", "dependencies": { - "@ant-design/icons": "^5.2.6", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@hookform/resolvers": "^3.3.1", diff --git a/frontend/src/components/slider/Sidenav.tsx b/frontend/src/components/slider/Sidenav.tsx index bebc8af..53dc3f0 100644 --- a/frontend/src/components/slider/Sidenav.tsx +++ b/frontend/src/components/slider/Sidenav.tsx @@ -24,11 +24,7 @@ import { useAppDispatch, useAppSelector } from "@/app/hooks"; import FactoryFlowIcon from "@/assets/images/FactryFlow.svg"; import FFLogo from "@/assets/images/FFlogo.svg"; -import { - setActiveMenuItem, - setMenuItems, - toggleChildrenOpen, -} from "@/redux/features/menuSlice"; +import { toggleChildrenOpen } from "@/redux/features/menuSlice"; import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight"; const drawerWidth = 240; @@ -83,9 +79,11 @@ const Drawer = styled(MuiDrawer, { const Sidenav = () => { const dispatch = useAppDispatch(); const location = useLocation(); + + const pathParts = location.pathname.split("/"); + const pathresult = `/${pathParts[1]}`; + const menuItems = useAppSelector((state) => state.menu.menuItems); - const activeitem = useAppSelector((state) => state.menu.activeMenuItem); - console.log(activeitem, "activeitem"); // const newMenuItems = [ // { @@ -152,12 +150,10 @@ const Sidenav = () => { // ]; const handleMenuItemClick = (menuItem: any) => { - console.log(menuItem, "menuItems"); if (menuItem.children) { dispatch(toggleChildrenOpen(menuItems.indexOf(menuItem))); } else { navigate(menuItem.route); - dispatch(setActiveMenuItem(menuItem)); } }; const theme = useTheme(); @@ -191,6 +187,8 @@ const Sidenav = () => { disablePadding sx={{ display: "block", + color: + location.pathname === menuItem.route ? "#007BFF" : "black", }} onClick={() => handleMenuItemClick(menuItem)} > @@ -238,7 +236,10 @@ const Sidenav = () => { handleMenuItemClick(child)} > { minHeight: 48, justifyContent: open ? "initial" : "center", px: 2.5, + color: + pathresult === child.route ? "#007BFF" : "black", }} > { }); const onSubmit = (data: any) => { - console.log(data, "Data"); if (isEdit) { updateTemplate({ id: params.id, data }); } else { diff --git a/frontend/src/pages/auth/Login.tsx b/frontend/src/pages/auth/Login.tsx index 0945658..5e72fb2 100644 --- a/frontend/src/pages/auth/Login.tsx +++ b/frontend/src/pages/auth/Login.tsx @@ -1,4 +1,3 @@ -import Link from "@mui/material/Link"; import Grid from "@mui/material/Grid"; import Typography from "@mui/material/Typography"; @@ -7,14 +6,20 @@ import { useEffect, useState } from "react"; import { useAppDispatch } from "../../app/hooks"; import { toast } from "react-toastify"; import { setUser } from "@/redux/features/authSlice"; -import { useNavigate, useLocation, Navigate } from "react-router-dom"; +import { useNavigate, useLocation, Navigate, Link } from "react-router-dom"; import * as yup from "yup"; import { useForm, SubmitHandler, Controller } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; -import { Box, Card, InputLabel, TextField } from "@mui/material"; +import { + Box, + Card, + Checkbox, + FormControlLabel, + InputLabel, + TextField, +} from "@mui/material"; import LoadingButton from "@mui/lab/LoadingButton/LoadingButton"; import type { Login } from "@/types/api.types"; -import { FormInputText } from "@/components/form-components/FormInputText"; const LogIn = () => { if (localStorage.getItem("token")) { @@ -27,6 +32,7 @@ const LogIn = () => { const location = useLocation(); const dispatch = useAppDispatch(); + const [isChecked, setIsChecked] = useState(false); const validationSchema = yup.object().shape({ username: yup.string().required("required username"), @@ -55,6 +61,10 @@ const LogIn = () => { } = form; const onSubmit: SubmitHandler = async (data) => { + if (!isChecked) { + toast.error("You must accept the Terms & Conditions"); + return; + } await loginUser(data); }; @@ -71,8 +81,6 @@ const LogIn = () => { if (error) toast.error((error as unknown as any).data.detail as string); }, [isLoading, data, isSuccess, error]); - const [isChecked, setIsChecked] = useState(false); - const handleCheckboxChange = () => { setIsChecked(!isChecked); }; @@ -228,15 +236,19 @@ const LogIn = () => { )} /> - - - - I Accept the Terms & Conditions - + + + } + label="I Accept the Terms & Conditions" + htmlFor="accept-terms" + sx={{ color: "#181C32", fontWeight: 600, fontSize: "14px" }} + /> { Sign In - + Already have an Account? - {" Sign Up"} + + Sign up + diff --git a/frontend/src/pages/auth/Register.tsx b/frontend/src/pages/auth/Register.tsx index de4b82a..abf59e4 100644 --- a/frontend/src/pages/auth/Register.tsx +++ b/frontend/src/pages/auth/Register.tsx @@ -1,20 +1,25 @@ -import Link from "@mui/material/Link"; import Grid from "@mui/material/Grid"; import Typography from "@mui/material/Typography"; import { yupResolver } from "@hookform/resolvers/yup"; import { Controller, useForm } from "react-hook-form"; -import { Box, Card, InputLabel, TextField } from "@mui/material"; +import { + Box, + Card, + Checkbox, + FormControlLabel, + InputLabel, + TextField, +} from "@mui/material"; import * as yup from "yup"; import { useRegisterUserMutation } from "@/redux/api/authApi"; -import { Navigate, useNavigate } from "react-router-dom"; +import { Navigate, useNavigate, Link } from "react-router-dom"; import { useAppDispatch } from "../../app/hooks"; import { useEffect, useState } from "react"; import { toast } from "react-toastify"; import LoadingButton from "@mui/lab/LoadingButton/LoadingButton"; -import { FormInputText } from "@/components/form-components/FormInputText"; export default function Register() { if (localStorage.getItem("token")) { @@ -25,6 +30,7 @@ export default function Register() { useRegisterUserMutation(); const navigate = useNavigate(); const dispatch = useAppDispatch(); + const [isChecked, setIsChecked] = useState(false); const validationSchema = yup.object().shape({ username: yup.string().required("required username"), @@ -49,6 +55,10 @@ export default function Register() { } = form; const onSubmit = async (data: any) => { + if (!isChecked) { + toast.error("You must accept the Terms & Conditions"); + return; + } await registerUser(data); }; @@ -61,8 +71,6 @@ export default function Register() { } }, [isSuccess]); - const [isChecked, setIsChecked] = useState(false); - const handleCheckboxChange = () => { setIsChecked(!isChecked); }; @@ -110,8 +118,8 @@ export default function Register() { sx={{ width: "800px", maxWidth: "100%", - height: "500px", - marginTop: 8, + height: "80%", + marginTop: 5, display: "flex", flexDirection: "column", alignItems: "center", @@ -258,15 +266,19 @@ export default function Register() { /> - - - - I Accept the Terms & Conditions - + + + } + label="I Accept the Terms & Conditions" + htmlFor="accept-terms" + sx={{ color: "#181C32", fontWeight: 600, fontSize: "14px" }} + /> - + Already have an Account? - {" Sign in"} + + Sign In + diff --git a/frontend/src/redux/api/jobApi.ts b/frontend/src/redux/api/jobApi.ts index 3686ffc..78ecad5 100644 --- a/frontend/src/redux/api/jobApi.ts +++ b/frontend/src/redux/api/jobApi.ts @@ -1,8 +1,7 @@ import { createApi } from "@reduxjs/toolkit/query/react"; import { - JobResponse, - JobError, + JobApiResponse, CreateJob, UpdateJob, GenericResponse, @@ -14,11 +13,11 @@ export const jobApi = createApi({ tagTypes: ["getAllJobs"], endpoints: (builder) => ({ // getAllJobs Api - getAllJobs: builder.query({ + getAllJobs: builder.query({ query: () => { return `api/jobs/`; }, - transformResponse: (res: GenericResponse) => { + transformResponse: (res: { items: JobApiResponse[] }) => { const result = res.items; return result ?? []; }, @@ -35,7 +34,7 @@ export const jobApi = createApi({ }), // create job api createJobs: builder.mutation< - GenericResponse, + GenericResponse, Partial >({ query: (body: any) => { @@ -58,10 +57,7 @@ export const jobApi = createApi({ invalidatesTags: ["getAllJobs"], }), //update job Api - updateJobs: builder.mutation< - GenericResponse, - UpdateJob - >({ + updateJobs: builder.mutation, UpdateJob>({ query: ({ id, data }) => { return { url: `api/jobs/${id}`, diff --git a/frontend/src/redux/features/menuSlice.ts b/frontend/src/redux/features/menuSlice.ts index 85ff77b..4921c9d 100644 --- a/frontend/src/redux/features/menuSlice.ts +++ b/frontend/src/redux/features/menuSlice.ts @@ -13,13 +13,11 @@ interface MenuItem { interface MenuState { menu: boolean; menuItems: MenuItem[]; - activeMenuItem: null; } const initialState: MenuState = { menu: false, - menuItems: [], // Initial state can be empty or pre-populated with some menu items - activeMenuItem: null, + menuItems: [], }; const menuSlice = createSlice({ @@ -38,12 +36,8 @@ const menuSlice = createSlice({ state.menuItems[index].childrenOpen = !state.menuItems[index].childrenOpen; }, - setActiveMenuItem: (state, action) => { - state.activeMenuItem = action.payload; - }, }, }); -export const { setMenu, setMenuItems, toggleChildrenOpen, setActiveMenuItem } = - menuSlice.actions; +export const { setMenu, setMenuItems, toggleChildrenOpen } = menuSlice.actions; export default menuSlice.reducer; diff --git a/frontend/src/types/api.types.ts b/frontend/src/types/api.types.ts index e68659f..a3a336f 100644 --- a/frontend/src/types/api.types.ts +++ b/frontend/src/types/api.types.ts @@ -44,14 +44,79 @@ type Nullable = T | null; //#endregion -//#region job api types -export type JobError = { - name: Array; -}; +interface TaskStatus { + id: number; + name: string; +} + +interface TaskType { + id: number; + name: string; +} -export type JobResponse = { +interface WorkCenter { id: number; name: string; +} + +interface Task { + id: number; + external_id: string; + name: string; + task_status: TaskStatus; + task_type: TaskType; + setup_time: number; + run_time_per_unit: number; + teardown_time: number; + quantity: number; + item: string; + planned_start_datetime: string; + planned_end_datetime: string; + created_at: string; + created_by: number; + updated_at: string; + updated_by: number; + work_center: WorkCenter; + job: { + id: number; + name: string; + priority: number; + }; + predecessor_ids: number[]; + successor_ids: number[]; + dependency_ids: number[]; +} + +interface DependencyType { + id: number; + name: string; +} + +interface DependencyStatus { + id: number; + name: string; +} + +interface Dependency { + id: number; + name: string; + external_id: string; + expected_close_datetime: string; + actual_close_datetime: string; + notes: string; + dependency_type: DependencyType; + dependency_status: DependencyStatus; + created_at: string; + created_by: number; + updated_at: string; + updated_by: number; + job_ids: number[]; + task_ids: number[]; +} + +interface Job { + id: number; + description: string; customer: string; due_date: string; @@ -60,36 +125,74 @@ export type JobResponse = { planned_end_datetime: string; external_id: string; note: string; - job_status: any; - job_type: any; + job_status: { + id: number; + name: string; + }; + job_type: { + id: number; + name: string; + }; created_at: string; created_by: number; updated_at: string; updated_by: number; - deleted_at: string; - task_ids: any; - dependencies: any; + task_ids: number[]; + dependency_ids: number[]; + tasks: Task[]; + dependencies: Dependency[]; +} + +export type JobApiResponse = { + items: Job[]; }; -// id": 0, -// "name": "string", -// "description": "string", -// "customer": "string", -// "due_date": "2023-10-06", -// "priority": 0, -// "planned_start_datetime": "2023-10-06T11:31:13.137Z", -// "planned_end_datetime": "2023-10-06T11:31:13.137Z", -// "external_id": "string", -// "note": "string", -// "job_status": 0, -// "job_type": 0, -// "created_at": "2023-10-06T11:31:13.138Z", -// "created_by": 0, -// "updated_at": "2023-10-06T11:31:13.138Z", -// "updated_by": 0, -// "deleted_at": "2023-10-06T11:31:13.138Z", -// "is_active": true, -// "is_deleted": false +//#region job api types +// export type JobError = { +// name: Array; +// }; + +// export type JobResponse = { +// id: number; +// name: string; +// description: string; +// customer: string; +// due_date: string; +// priority: number; +// planned_start_datetime: string; +// planned_end_datetime: string; +// external_id: string; +// note: string; +// job_status: any; +// job_type: any; +// created_at: string; +// created_by: number; +// updated_at: string; +// updated_by: number; +// deleted_at: string; +// task_ids: any; +// dependencies: any; +// }; + +// // id": 0, +// // "name": "string", +// // "description": "string", +// // "customer": "string", +// // "due_date": "2023-10-06", +// // "priority": 0, +// // "planned_start_datetime": "2023-10-06T11:31:13.137Z", +// // "planned_end_datetime": "2023-10-06T11:31:13.137Z", +// // "external_id": "string", +// // "note": "string", +// // "job_status": 0, +// // "job_type": 0, +// // "created_at": "2023-10-06T11:31:13.138Z", +// // "created_by": 0, +// // "updated_at": "2023-10-06T11:31:13.138Z", +// // "updated_by": 0, +// // "deleted_at": "2023-10-06T11:31:13.138Z", +// // "is_active": true, +// // "is_deleted": false export type CreateJob = { name: string; @@ -107,31 +210,31 @@ export type UpdateJob = { id: string; data: Partial; }; -//#endregion +// //#endregion -export type DependencyResponse = { - id: number; - external_id: Nullable; - name: string; - dependency_type: number; - dependency_status: number; - expected_close_datetime: Nullable; - actual_close_datetime: Nullable; - notes: Nullable; - created_at: Nullable; - created_by: number; - updated_at: Nullable; - updated_by: number; - deleted_at: Nullable; - is_active: boolean; - is_deleted: boolean; -}; +// export type DependencyResponse = { +// id: number; +// external_id: Nullable; +// name: string; +// dependency_type: number; +// dependency_status: number; +// expected_close_datetime: Nullable; +// actual_close_datetime: Nullable; +// notes: Nullable; +// created_at: Nullable; +// created_by: number; +// updated_at: Nullable; +// updated_by: number; +// deleted_at: Nullable; +// is_active: boolean; +// is_deleted: boolean; +// }; -export type DependencyStatusResponse = { - id: number; - name: string; - created_at: Nullable; - created_by: any; - updated_at: Nullable; - updated_by: any; -}; +// export type DependencyStatusResponse = { +// id: number; +// name: string; +// created_at: Nullable; +// created_by: any; +// updated_at: Nullable; +// updated_by: any; +// }; From b8725fe042cb674e9814cc85371f172bd5bd4fa6 Mon Sep 17 00:00:00 2001 From: manish Date: Mon, 6 Nov 2023 18:08:22 +0530 Subject: [PATCH 2/2] sidebar design add and login and signup page customize the code --- frontend/src/App.tsx | 80 ++++---- frontend/src/assets/images/delete.png | Bin 0 -> 2070 bytes frontend/src/assets/sidebar/dashboard.svg | 4 +- frontend/src/assets/sidebar/description.svg | 4 +- frontend/src/assets/sidebar/production.svg | 6 +- frontend/src/assets/sidebar/resource.svg | 6 +- frontend/src/assets/sidebar/settings.svg | 4 +- frontend/src/assets/sidebar/support_agent.svg | 6 +- frontend/src/components/PrivateRoutes.tsx | 25 --- frontend/src/components/requireUser.tsx | 42 ++--- frontend/src/components/slider/Navbar.tsx | 13 +- frontend/src/components/slider/Sidenav.tsx | 173 ++++++++---------- .../table/Model/delete-model/index.css | 50 ++--- .../table/Model/delete-model/index.tsx | 14 +- frontend/src/index.css | 3 +- frontend/src/middleware/AuthorizedUser.tsx | 53 +----- frontend/src/pages/Jobs/Form.tsx | 2 +- frontend/src/pages/Jobs/index.tsx | 78 ++++---- frontend/src/pages/auth/ChangePass.tsx | 115 ++++++------ frontend/src/pages/auth/Login.tsx | 4 +- frontend/src/redux/api/authApi.ts | 2 +- frontend/src/redux/api/customeFetchBase.ts | 10 - frontend/src/redux/api/jobApi.ts | 36 ++-- frontend/src/redux/api/userApi.ts | 3 +- frontend/src/redux/features/authSlice.ts | 6 +- frontend/src/types/api.types.ts | 39 ++-- 26 files changed, 344 insertions(+), 434 deletions(-) create mode 100644 frontend/src/assets/images/delete.png delete mode 100644 frontend/src/components/PrivateRoutes.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1a783fd..057263f 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3,7 +3,6 @@ import Login from "./pages/auth/Login"; import Register from "./pages/auth/Register"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; -import PrivateRoutes from "./components/PrivateRoutes"; import Jobs from "./pages/Jobs"; import Tasks from "./pages/Tasks"; import JobForm from "./pages/Jobs/Form"; @@ -39,6 +38,7 @@ import Dote from "@/assets/images/Dote.svg"; import { setMenuItems } from "@/redux/features/menuSlice"; import { useEffect } from "react"; import { useAppDispatch } from "./app/hooks"; +import UnauthorizePage from "./pages/UnAuthorized"; function App() { const dispatch = useAppDispatch(); const newMenuItems = [ @@ -116,6 +116,7 @@ function App() { } /> } /> + } /> } /> } /> @@ -127,50 +128,63 @@ function App() { - }> - } /> + }> + }> + } /> + - }> - } /> - } /> - } /> + }> + }> + } /> + } /> + } /> + - }> - } /> - } /> - } /> - }> - } /> - } /> - } /> + }> + }> + } /> + } /> + } /> + }> + } /> + } /> + } /> + - }> - } /> - } /> - } /> + }> + }> + } /> + } /> + } /> + - }> - } /> - } /> - } /> + }> + }> + } /> + } /> + } /> + - - }> - } /> - } /> - } /> - } /> + }> + }> + } /> + } /> + } /> + } /> + - }> - } /> - } /> - } /> + }> + }> + } /> + } /> + } /> + diff --git a/frontend/src/assets/images/delete.png b/frontend/src/assets/images/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..a643356689742d3cedfae1c4235255823e21033c GIT binary patch literal 2070 zcmV+x2EMr?vh|@T3QZbWs%rKKwR4}+OLt&?)pnx{X&{L!iGf4|2(8%dcXmAxK z1zq?DAW+2khx|)F?#Jf6m5eRvWZmh0t?d2GVC1uGS^M>SZ{ObTdki#3O3C2Pof3Tb zAYg7zz|M|A~@hU6L5Gqk-7jwUmOLJvIVw% z$W~WdP%woFqFm9Sa}y>g%b*NGsg zqt)!?Elh5LsMz3nvnno(6FCc$xgg3lEiO(&xqJb}nVf{lR1kUX+69=Hn9|xc#i0{p zP?S1kL?(iat$T_J&B`omCktyyU63#UN-5a4h82 zs}>|+WD8MZ%+G&*=7V=!DA@1rZjQQWIg%hoj3FctCAJ_cW{{gQVw?_%QYw9n8&hHl zVgh(fMhNur{>qIQ@u0E7bU@{35s55_ym4d3h%o|`n^D3Xkw}85<&g81fu{+Mof^Xk z3>8Gh4O*KrBm>7#jpY!ATL`V%ni*AcXbfpAhj8jZqoU*^7A>r4oNqFO7917<*Vr5 zV86{&z;=M&?7iG)A(>l;=iLX%?!!31PUd^UxYj$zZ?X=rQ4m)jbKlQ4ijtwe$*71B+K7Ph3At zkhi&sLD1P4%(m#^u>xkzsyOJNQU@i7ym!wwH=haw$Np$(zHK4f+llrP8B&1GRl-pW zvF!;A=%6jM)Di@hzUz+jF7k6Z$M|HWwg)$LDix(gTabF4To!0c0C$0j{tVxR{slu? zBV*!^{+}U#!jJh*7~T6c5D_%-T6DFPr$G3yX^m$6#_kj}YjH@8epE z5XN2U!rYwTc#qduh%W5x2(!IMCor&+AjW0sf^GA5i6es^pcdThO4JC{!ib?6Mi9*~ zf@lU;XWC;#qfFfhq6-@v zK8IGz2%-y>ipybrz3}3}h7Q%L%NcDUpb`*z1$W z{w!P2nUZMdN=kwb*j#~eg5pQ#tl{x$Z==xwLou9);m3kZO&LLo<5TJKPlBiuJe^2y z$Psc^CmP9g-=Hd&jg{n0yMfH{r(IuMT|I=Qr3<-ie2{WCWSUfgmY452_TqQ_cde9k z2|`)Bblo}%l700!$=-!bTd9m-@r4B#itya7l22>Gxd zc5z@tQ)OZEszmAqD;T}*;&1Z}6oEt`fISBuJkI4DV%s`uVP6_72wBh4(wy09nleMG zT@M^=b)TeC*#|?qw3~_zy#F+G5{`?G7fqFiln|ncVr-rEl;Q4(0=(JXn4I<))`mT8 zs36L`jO$7cb##l+B_UG4W>20RP&YC#j7GV95VgHt^cmFJ+P+y09syd-efBK!R64RC zYSvXQZ<`$|G3ZQj<9ti397Fj)dI1yUheKmDLK{8P6f6r!jQ8)i*z4D^UA$?Vmo^E+ zAQIi3F{1R4Pz)l`K&lrml|Gt45A6U>ZSoR`L8RB5_&j%TE0tV)|JzzLCq7B8OZK{e zNgq6YxTM4MK}*a;kR;dTCYNId5@<@W64Jc(12%au<40Xjk4( zt&e^EwWV4(I8ORq8%O}!;7sQ#E0soGu^}qj*IQIgvsPAYRq%OkPT*hi(FSn=&1Qdz zLh}EmQh>LdrCMK_o%N|gf+~>k@@2CqR}_{10b5fkQn0cw=>Px#07*qoM6N<$f`9PF AIsgCw literal 0 HcmV?d00001 diff --git a/frontend/src/assets/sidebar/dashboard.svg b/frontend/src/assets/sidebar/dashboard.svg index 9119368..91ef78e 100644 --- a/frontend/src/assets/sidebar/dashboard.svg +++ b/frontend/src/assets/sidebar/dashboard.svg @@ -1,3 +1,3 @@ - - + + diff --git a/frontend/src/assets/sidebar/description.svg b/frontend/src/assets/sidebar/description.svg index fa160fe..48a61a6 100644 --- a/frontend/src/assets/sidebar/description.svg +++ b/frontend/src/assets/sidebar/description.svg @@ -1,3 +1,3 @@ - - + + diff --git a/frontend/src/assets/sidebar/production.svg b/frontend/src/assets/sidebar/production.svg index 3feb290..5d07807 100644 --- a/frontend/src/assets/sidebar/production.svg +++ b/frontend/src/assets/sidebar/production.svg @@ -1,8 +1,8 @@ - + - + - + diff --git a/frontend/src/assets/sidebar/resource.svg b/frontend/src/assets/sidebar/resource.svg index a48742f..0182cce 100644 --- a/frontend/src/assets/sidebar/resource.svg +++ b/frontend/src/assets/sidebar/resource.svg @@ -1,8 +1,8 @@ - + - + - + diff --git a/frontend/src/assets/sidebar/settings.svg b/frontend/src/assets/sidebar/settings.svg index e83801d..7823878 100644 --- a/frontend/src/assets/sidebar/settings.svg +++ b/frontend/src/assets/sidebar/settings.svg @@ -1,3 +1,3 @@ - - + + diff --git a/frontend/src/assets/sidebar/support_agent.svg b/frontend/src/assets/sidebar/support_agent.svg index 489a3ba..35eb888 100644 --- a/frontend/src/assets/sidebar/support_agent.svg +++ b/frontend/src/assets/sidebar/support_agent.svg @@ -1,8 +1,8 @@ - + - + - + diff --git a/frontend/src/components/PrivateRoutes.tsx b/frontend/src/components/PrivateRoutes.tsx deleted file mode 100644 index 72bf1f4..0000000 --- a/frontend/src/components/PrivateRoutes.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useEffect, useState } from "react"; -import { Outlet, Navigate } from "react-router-dom"; - -const PrivateRoutes = () => { - // const token = JSON.parse(localStorage.getItem("token") || "{}"); - // return token ? : ; - - const [token, setToken] = useState(null); - const [isAuthenticated, setIsAuthenticated] = useState(true); - - useEffect(() => { - const _token = localStorage.getItem("token"); - if (_token) { - setToken(_token); - } - }, []); - - useEffect(() => { - // [TODO] fetch auth profile - }, [token]); - - return isAuthenticated ? : ; -}; - -export default PrivateRoutes; diff --git a/frontend/src/components/requireUser.tsx b/frontend/src/components/requireUser.tsx index 012a20f..5128264 100644 --- a/frontend/src/components/requireUser.tsx +++ b/frontend/src/components/requireUser.tsx @@ -2,34 +2,30 @@ import { Navigate, Outlet, useLocation } from "react-router-dom"; import Loading from "./loading/loading"; import { userApi } from "@/redux/api"; -const RequireUser = () => { +const requireUser = () => { const location = useLocation(); + const isAuthenticated = !!localStorage.getItem("token"); + const { isLoading, isFetching } = userApi.endpoints.getMe.useQuery(null, { + skip: false, + refetchOnMountOrArgChange: true, + }); + const loading = isLoading || isFetching; - const tokenInLocalStorage = () => { - const token = localStorage.getItem("token"); - return token && JSON.parse(token).access; - }; + const user = userApi.endpoints.getMe.useQueryState(null, { + selectFromResult: ({ data }) => data!, + }); - const { - data: user, - isLoading, - isFetching, - } = tokenInLocalStorage() - ? userApi.endpoints.getMe.useQuery(null) - : { data: null, isLoading: false, isFetching: false }; - - // Show loading indicator while fetching data - if (isLoading || isFetching) { + if (loading) { return ; } - // Check if user data exists from API call - if (user) { - return ; - } - - // Redirect if user is not authenticated - return ; + return isAuthenticated || user ? ( + + ) : isAuthenticated && user ? ( + + ) : ( + + ); }; -export default RequireUser; +export default requireUser; diff --git a/frontend/src/components/slider/Navbar.tsx b/frontend/src/components/slider/Navbar.tsx index deb8e08..c8619ba 100644 --- a/frontend/src/components/slider/Navbar.tsx +++ b/frontend/src/components/slider/Navbar.tsx @@ -74,7 +74,7 @@ export default function Navbar() { React.useState(null); const dopen = useAppSelector((state) => state.menu.menu); - + const user = useAppSelector((state) => state.auth.user); const isMenuOpen = Boolean(anchorEl); const isMobileMenuOpen = Boolean(mobileMoreAnchorEl); @@ -178,12 +178,13 @@ export default function Navbar() { onClick={() => dispatch(setMenu(!dopen))} sx={{ backgroundColor: "#F1F1F2", - borderRadius: "10px", - width: "40px", - height: "40px", + borderRadius: "6px", + padding: "6px", + width: "48px", + height: "48px", }} > - menuIcon + menuIcon - J +

{user ? `${user.username}`.charAt(0).toUpperCase() : ""}

diff --git a/frontend/src/components/slider/Sidenav.tsx b/frontend/src/components/slider/Sidenav.tsx index 53dc3f0..04b66ae 100644 --- a/frontend/src/components/slider/Sidenav.tsx +++ b/frontend/src/components/slider/Sidenav.tsx @@ -1,4 +1,3 @@ -import { useEffect, useState } from "react"; import { styled, useTheme, Theme, CSSObject } from "@mui/material/styles"; import Box from "@mui/material/Box"; import MuiDrawer from "@mui/material/Drawer"; @@ -9,15 +8,10 @@ import { ListItemButton, ListItem, List, - IconButton, - Divider, - SvgIcon, + Typography, } from "@mui/material"; import CssBaseline from "@mui/material/CssBaseline"; -import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; -import ChevronRightIcon from "@mui/icons-material/ChevronRight"; -// import ExpandLessIcon from "@mui/icons-material/ExpandLess"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { useLocation, useNavigate } from "react-router-dom"; import { useAppDispatch, useAppSelector } from "@/app/hooks"; @@ -26,6 +20,7 @@ import FactoryFlowIcon from "@/assets/images/FactryFlow.svg"; import FFLogo from "@/assets/images/FFlogo.svg"; import { toggleChildrenOpen } from "@/redux/features/menuSlice"; import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight"; +import { FiberManualRecord as DotIcon } from "@mui/icons-material"; const drawerWidth = 240; @@ -36,6 +31,8 @@ const openedMixin = (theme: Theme): CSSObject => ({ duration: theme.transitions.duration.enteringScreen, }), overflowX: "hidden", + paddingLeft: "10px", + paddingRight: "10px", }); const closedMixin = (theme: Theme): CSSObject => ({ @@ -44,6 +41,8 @@ const closedMixin = (theme: Theme): CSSObject => ({ duration: theme.transitions.duration.leavingScreen, }), overflowX: "hidden", + paddingLeft: "10px", + paddingRight: "10px", width: `calc(${theme.spacing(7)} + 1px)`, [theme.breakpoints.up("sm")]: { width: `calc(${theme.spacing(8)} + 1px)`, @@ -55,7 +54,6 @@ const DrawerHeader = styled("div")(({ theme }) => ({ alignItems: "center", justifyContent: "flex-end", padding: theme.spacing(0, 1), - // necessary for content to be below app bar ...theme.mixins.toolbar, })); @@ -85,70 +83,6 @@ const Sidenav = () => { const menuItems = useAppSelector((state) => state.menu.menuItems); - // const newMenuItems = [ - // { - // label: "Dashboard", - // icon: DashboardIcon, - // route: "/dashboard", - // }, - // { - // label: "Production", - // icon: ProductionIcon, - // childrenOpen: false, - // route: "/production", - // children: [ - // { - // label: "Jobs", - // icon: Dote, - // route: "/jobs", - // }, - // { - // label: "Tasks", - // icon: Dote, - // route: "/tasks", - // }, - // { - // label: "Dependency", - // icon: Dote, - // route: "/dependency", - // }, - // ], - // }, - // { - // label: "Resource", - // icon: ResourceIcon, - // childrenOpen: false, - // route: "/resource", - // children: [ - // { - // label: "Template", - // icon: Dote, - // route: "/template", - // }, - // { - // label: "Resources", - // icon: Dote, - // route: "/resources", - // }, - // { - // label: "Exception", - // icon: Dote, - // route: "/exception", - // }, - // ], - // }, - // { - // label: "Settings", - // icon: SettingIcon, - // route: "/settings", - // }, - // { - // label: "Help & Support", - // icon: SupportIcon, - // route: "/help", - // }, - // ]; - const handleMenuItemClick = (menuItem: any) => { if (menuItem.children) { dispatch(toggleChildrenOpen(menuItems.indexOf(menuItem))); @@ -157,17 +91,16 @@ const Sidenav = () => { } }; const theme = useTheme(); - // const [open, setOpen] = React.useState(true); + const navigate = useNavigate(); const open = useAppSelector((state) => state.menu.menu); - // const open = useAppStore((state) => state.dopen); return ( - + {open && open ? ( { width={200} /> ) : ( - FFlogo + FFlogo )} @@ -188,7 +121,18 @@ const Sidenav = () => { sx={{ display: "block", color: - location.pathname === menuItem.route ? "#007BFF" : "black", + location.pathname === menuItem.route + ? "#023E8A" + : "#5E6278", + background: + location.pathname === menuItem.route ? "#023E8A0D" : "#FFF", + borderLeft: + location.pathname === menuItem.route + ? "3px solid #023E8A" + : "", + borderRadius: + location.pathname === menuItem.route ? "8px" : "", + marginTop: "10px", }} onClick={() => handleMenuItemClick(menuItem)} > @@ -211,18 +155,39 @@ const Sidenav = () => { alt={menuItem.label} height={30} width={24} + style={{ + filter: + location.pathname === menuItem.route + ? "invert(14%) sepia(69%) saturate(3330%) hue-rotate(205deg) brightness(92%) contrast(98%)" + : "none", + }} />
+ {menuItem.label} + + } + sx={{ + opacity: open ? 1 : 0, + }} /> - {menuItem.children && - (menuItem.childrenOpen ? ( - - ) : ( - - ))} + { + menuItem.children && open ? ( + menuItem.childrenOpen ? ( + + ) : open ? ( + + ) : null // Hide the submenu arrow icon when the submenu is open + ) : null /* Hide the submenu icons when the menu is closed */ + }
{menuItem.children && ( @@ -230,6 +195,7 @@ const Sidenav = () => { in={menuItem.childrenOpen} timeout="auto" unmountOnExit + sx={{ "& .MuiList-root": { padding: "0px !important" } }} > {menuItem.children.map((child: any, childIndex: any) => ( @@ -239,6 +205,8 @@ const Sidenav = () => { sx={{ display: "block", pl: 4, + padding: 0, + margin: 0, }} onClick={() => handleMenuItemClick(child)} > @@ -248,7 +216,9 @@ const Sidenav = () => { justifyContent: open ? "initial" : "center", px: 2.5, color: - pathresult === child.route ? "#007BFF" : "black", + pathresult === child.route + ? "#023E8A" + : "#5E6278", }} > { justifyContent: "center", }} > - {child.label} + + {child.label} + + } + sx={{ + opacity: open ? 1 : 0, + }} /> diff --git a/frontend/src/components/table/Model/delete-model/index.css b/frontend/src/components/table/Model/delete-model/index.css index b92b0f1..ce4fbf9 100644 --- a/frontend/src/components/table/Model/delete-model/index.css +++ b/frontend/src/components/table/Model/delete-model/index.css @@ -1,21 +1,22 @@ -.main-model{ +.main-model { height: 300px; - } -.h3{ +.h3 { font-size: 20px !important; - color: #3F4254; + color: #5E6278 !important; } -.h6{ +.h6 { color: #7E8299 !important; line-height: 22px !important; + font-weight: 400 !important; } -.frist_row{ + +.frist_row { padding: 10px; gap: 15px; - + display: flex; flex-direction: column; text-align: center; @@ -23,38 +24,41 @@ justify-content: center; } -h3{ +h3 { font-size: 16px; } - -.delete-icon{ - background-color: #FFF5F8 !important; +.delete-icon { + background-color: #FF4D4F1A !important; border-radius: 50% !important; - width: 60px !important; - height: 60px !important; + width: 100px !important; + height: 100px !important; } -.btn-model-row{ +.btn-model-row { display: flex; justify-content: center; margin-top: 15px; gap: 25px; } + .btn-cancel-model { height: 48px; - width: 110px; - font-size: 17px; - background-color:#F1F1F2 !important; + width: 150px; + font-size: 16px !important; + padding: 16px 24px !important; + background-color: #F9F9F9 !important; color: #7E8299 !important; box-shadow: none !important; } -.btn-delete-model{ + +.btn-delete-model { height: 48px; - width: 110px; - font-size: 19px; + width: 150px; + font-size: 16px !important; + padding: 16px 24px !important; text-transform: capitalize !important; - background-color:#F1416C !important; - color: #fff !important; - box-shadow: none !important; + background-color: #FF4D4F !important; + color: #FFF !important; + box-shadow: none !important; } \ No newline at end of file diff --git a/frontend/src/components/table/Model/delete-model/index.tsx b/frontend/src/components/table/Model/delete-model/index.tsx index 2ff13a9..d977d6f 100644 --- a/frontend/src/components/table/Model/delete-model/index.tsx +++ b/frontend/src/components/table/Model/delete-model/index.tsx @@ -1,9 +1,9 @@ import React from "react"; import "./index.css"; -import { useDisclosure } from "@mantine/hooks"; + import { Modal, Button } from "@mantine/core"; import { Box, IconButton, Typography } from "@mui/material"; -import Deleteicon from "@/assets/images/delete.svg"; +import Deleteicon from "@/assets/images/delete.png"; import LoadingButton from "@mui/lab/LoadingButton/LoadingButton"; const DeleteModel = ({ deleteModel, @@ -30,27 +30,27 @@ const DeleteModel = ({ onClick={() => {}} className="delete-icon" > - Deleteicon + Deleteicon Are you sure you want to delete? - By deleting “Loreum Ipsum” Job, all task inside that column - will also be deleted. + By deleting “Loreum Ipsum”{" "} + Job, all task inside that column will also be deleted. = ({ children }) => { -// const authProfile = useAppSelector((state) => state.user.profile); - -// const { data, isLoading, error, isError } = useGetProfileQuery(undefined); - -// useEffect(() => { -// if (!isLoading && error) { -// toast.error("Unauthorized Token"); -// } -// if (!isLoading && data) setProfile(data); -// }, [isLoading, data, error]); - -// if (isLoading) { -// return Loading...; -// } - -// if (authProfile) { -// return
{children}
; -// } - -// return ; -// }; - -// export default AuthorizedUser; - import Loading from "@/components/loading/loading"; import { userApi } from "@/redux/api"; import React from "react"; -// import { useCookies } from "react-cookie"; -// import Loading from "@/components/loading/loading"; -import { Navigate } from "react-router-dom"; - type IAuthMiddleware = { children: React.ReactElement; }; const AuthMiddleware: React.FC = ({ children }) => { - let userprofile = false; - - if (localStorage.getItem("token")) { - const { access } = JSON.parse(localStorage.getItem("token") as string); - - if (access) { - userprofile = true; - } - } + const isAuthenticated = !!localStorage.getItem("token"); const { isLoading } = userApi.endpoints.getMe.useQuery(null, { - skip: !userprofile, + skip: isAuthenticated, }); if (isLoading) { return ; } - return children; }; diff --git a/frontend/src/pages/Jobs/Form.tsx b/frontend/src/pages/Jobs/Form.tsx index 768b9f4..2ce1d15 100644 --- a/frontend/src/pages/Jobs/Form.tsx +++ b/frontend/src/pages/Jobs/Form.tsx @@ -237,7 +237,7 @@ const MyForm = () => { }; console.log(requestObj, "requestObject"); const response = await createDependency(requestObj); - if (response && dependencyIsSuccess) { + if (response) { getjobid(); } } diff --git a/frontend/src/pages/Jobs/index.tsx b/frontend/src/pages/Jobs/index.tsx index 0e06fb3..47a0f9f 100644 --- a/frontend/src/pages/Jobs/index.tsx +++ b/frontend/src/pages/Jobs/index.tsx @@ -12,7 +12,7 @@ import { setJobies, setJobStatus } from "@/redux/features/jobSlice"; import Loading from "@/components/loading/loading"; import useTabs from "@/hooks/useTabs"; import { getString } from "@/helpers"; -import { JobResponse } from "@/types/api.types"; +import { Job } from "@/types/api.types"; import deleteicon from "@/assets/images/delete.svg"; import editicon from "@/assets/images/border_color.svg"; import viewicon from "@/assets/images/visibility.svg"; @@ -38,16 +38,11 @@ type excluded_fields = | "is_active" | "is_deleted"; -interface WithJobResponse extends JobResponse { - customer: string; - status?: string; -} - const Jobs = () => { const dispatch = useAppDispatch(); const jobsSelector = useAppSelector((state: any) => state.job.jobies); const jobstatusSelector = useAppSelector((state: any) => state.job.jobstatus); - const [data, setData] = useState | []>(); + const [data, setData] = useState | undefined>(); //call api joblist const { data: getjobData, isLoading: jobLoading } = useGetAllJobsQuery(); @@ -63,7 +58,7 @@ const Jobs = () => { const [deleteModel, setDeleteModel] = useState(false); const [deleteId, setDeleteId] = useState(""); - const columns: GridColDef[] = [ + const columns: GridColDef[] = [ { field: "id", headerName: "ID" }, { field: "name", @@ -146,7 +141,7 @@ const Jobs = () => { flex: 1, headerAlign: "center", align: "center", - renderCell: (row) => { + renderCell: (row: any) => { const badgeColor: BadgeType = { completed: "green", "not-planned": "red", @@ -410,43 +405,38 @@ const Jobs = () => { jobstatus={jobstatusSelector} setFilterData={setData} /> */} - {jobLoading ? ( + + {getjobData && ( <> - - - ) : ( - getjobData && ( - <> - - - ) + }, + }} + slots={{ toolbar: GridToolbar }} + slotProps={{ + toolbar: { + showQuickFilter: true, + quickFilterProps: { debounceMs: 500 }, + }, + }} + pageSizeOptions={[5, 10, 25]} + checkboxSelection + disableRowSelectionOnClick + disableColumnFilter + disableColumnMenu + disableDensitySelector + disableColumnSelector + /> + )}
diff --git a/frontend/src/pages/auth/ChangePass.tsx b/frontend/src/pages/auth/ChangePass.tsx index dfcadf4..5e4548e 100644 --- a/frontend/src/pages/auth/ChangePass.tsx +++ b/frontend/src/pages/auth/ChangePass.tsx @@ -1,5 +1,12 @@ import React, { useEffect } from "react"; -import { Card, CardContent, Grid, TextField, Typography } from "@mui/material"; +import { + Box, + Card, + CardContent, + Grid, + TextField, + Typography, +} from "@mui/material"; import { Controller, useForm } from "react-hook-form"; import LoadingButton from "@mui/lab/LoadingButton/LoadingButton"; import { yupResolver } from "@hookform/resolvers/yup"; @@ -8,6 +15,7 @@ import * as yup from "yup"; import { useChangePasswordMutation } from "@/redux/api/authApi"; import { toast } from "react-toastify"; import Layout from "../Layout"; +import { FormInputText } from "@/components/form-components/FormInputText"; const validationSchema = yup.object().shape({ current_password: yup.string().required("Current Password is required"), @@ -16,108 +24,89 @@ const validationSchema = yup.object().shape({ const ChangePass = () => { const form = useForm({ + defaultValues: { current_password: "", new_password: "" }, resolver: yupResolver(validationSchema), }); const { control, handleSubmit, - setValue, - watch, reset, formState: { errors }, } = form; - const [changePassword, { isLoading, error, data }] = + const [changePassword, { isLoading, isSuccess, error, data }] = useChangePasswordMutation(); const onSubmit = (data: any) => { changePassword(data); - reset({ current_password: "", new_password: "" }); - // console.log(data, "Data"); + reset(); }; useEffect(() => { - if (!isLoading && data) { - data.code >= 400 - ? toast.error(data.message) - : toast.success(data.message); - } - }, [isLoading, error, data]); + if (!isLoading && data) toast.success(data.message); + if (error) console.log(error, "error"); + }, [error, isLoading]); return ( Change Password
- + - ( - - )} + label={"Current Password"} + placeholder={"Enter current password"} + type={"text"} /> - ( - - )} + label={"New Password"} + placeholder={"Enter new password"} + type={"text"} /> - {/* */} - - - Submit - + + Submit + + diff --git a/frontend/src/pages/auth/Login.tsx b/frontend/src/pages/auth/Login.tsx index 5e72fb2..e85161b 100644 --- a/frontend/src/pages/auth/Login.tsx +++ b/frontend/src/pages/auth/Login.tsx @@ -5,7 +5,7 @@ import { useLoginUserMutation } from "@/redux/api/authApi"; import { useEffect, useState } from "react"; import { useAppDispatch } from "../../app/hooks"; import { toast } from "react-toastify"; -import { setUser } from "@/redux/features/authSlice"; +import { setToken } from "@/redux/features/authSlice"; import { useNavigate, useLocation, Navigate, Link } from "react-router-dom"; import * as yup from "yup"; import { useForm, SubmitHandler, Controller } from "react-hook-form"; @@ -72,7 +72,7 @@ const LogIn = () => { useEffect(() => { if (!isLoading && data) { - dispatch(setUser(data)); + dispatch(setToken(data)); } if (isSuccess) { toast.success("You successfully logged in"); diff --git a/frontend/src/redux/api/authApi.ts b/frontend/src/redux/api/authApi.ts index f424a27..dd72328 100644 --- a/frontend/src/redux/api/authApi.ts +++ b/frontend/src/redux/api/authApi.ts @@ -47,7 +47,7 @@ export const authApi = createApi({ changePassword: builder.mutation({ query: (body) => { return { - url: "api/change-password/", + url: "api/users/change-password/", method: "put", body, headers: { diff --git a/frontend/src/redux/api/customeFetchBase.ts b/frontend/src/redux/api/customeFetchBase.ts index 1dedb83..b629922 100644 --- a/frontend/src/redux/api/customeFetchBase.ts +++ b/frontend/src/redux/api/customeFetchBase.ts @@ -84,16 +84,6 @@ const customFetchBase: BaseQueryFn< result = await baseQuery(args, api, extraOptions); } } - if ((result.error?.data as any)?.detail === "Unauthorized") { - api.dispatch(logout()); - window.location.href = "/"; - } - if ((result.error?.data as any)?.detail === "User not found") { - api.dispatch(logout()); - - window.location.href = "/"; - } - return result; }; diff --git a/frontend/src/redux/api/jobApi.ts b/frontend/src/redux/api/jobApi.ts index 78ecad5..b1d37e5 100644 --- a/frontend/src/redux/api/jobApi.ts +++ b/frontend/src/redux/api/jobApi.ts @@ -1,10 +1,12 @@ import { createApi } from "@reduxjs/toolkit/query/react"; import { - JobApiResponse, CreateJob, UpdateJob, GenericResponse, + JobStatusResponse, + JobTypeResonse, + Job, } from "@/types/api.types"; import customFetchBase from "./customeFetchBase"; export const jobApi = createApi({ @@ -13,19 +15,18 @@ export const jobApi = createApi({ tagTypes: ["getAllJobs"], endpoints: (builder) => ({ // getAllJobs Api - getAllJobs: builder.query({ + getAllJobs: builder.query({ query: () => { return `api/jobs/`; }, - transformResponse: (res: { items: JobApiResponse[] }) => { - const result = res.items; - return result ?? []; + transformResponse: (res: { items: Job[] }) => { + return res.items ?? []; }, providesTags: ["getAllJobs"], }), // getJobbyId Api - getJobById: builder.mutation({ + getJobById: builder.mutation({ query: (id: number) => { return { url: `api/jobs/${id}`, @@ -33,10 +34,7 @@ export const jobApi = createApi({ }, }), // create job api - createJobs: builder.mutation< - GenericResponse, - Partial - >({ + createJobs: builder.mutation>({ query: (body: any) => { return { url: "api/jobs/", @@ -47,7 +45,7 @@ export const jobApi = createApi({ invalidatesTags: ["getAllJobs"], }), // delete Job Api - deleteJobs: builder.mutation, number>({ + deleteJobs: builder.mutation({ query: (id) => { return { url: `api/jobs/${id}`, @@ -57,7 +55,7 @@ export const jobApi = createApi({ invalidatesTags: ["getAllJobs"], }), //update job Api - updateJobs: builder.mutation, UpdateJob>({ + updateJobs: builder.mutation({ query: ({ id, data }) => { return { url: `api/jobs/${id}`, @@ -69,24 +67,22 @@ export const jobApi = createApi({ }), //getJobStatus - getJobStatus: builder.query({ + getJobStatus: builder.query({ query: () => { return `api/job-status/`; }, - transformResponse: (res: any) => { - const { items } = res; - return items ?? []; + transformResponse: (res: { items: JobStatusResponse[] }) => { + return res.items ?? []; }, }), //getJobType - getJobType: builder.query({ + getJobType: builder.query({ query: () => { return `api/job-types/`; }, - transformResponse: (res: any) => { - const result = res.items; - return result ?? []; + transformResponse: (res: { items: JobTypeResonse[] }) => { + return res.items ?? []; }, }), }), diff --git a/frontend/src/redux/api/userApi.ts b/frontend/src/redux/api/userApi.ts index 4520dbe..469ae48 100644 --- a/frontend/src/redux/api/userApi.ts +++ b/frontend/src/redux/api/userApi.ts @@ -1,6 +1,7 @@ import { createApi } from "@reduxjs/toolkit/query/react"; import customFetchBase from "./customeFetchBase"; +import { setUser } from "../features/authSlice"; export const userApi = createApi({ reducerPath: "userApi", @@ -17,7 +18,7 @@ export const userApi = createApi({ async onQueryStarted(args, { dispatch, queryFulfilled }) { try { const { data } = await queryFulfilled; - // dispatch(setUser(data)); + dispatch(setUser(data)); } catch (error) {} }, }), diff --git a/frontend/src/redux/features/authSlice.ts b/frontend/src/redux/features/authSlice.ts index 332b2ac..7b13b5a 100644 --- a/frontend/src/redux/features/authSlice.ts +++ b/frontend/src/redux/features/authSlice.ts @@ -14,6 +14,9 @@ export const authSlice = createSlice({ initialState, reducers: { setUser: (state, action: PayloadAction) => { + state.user = action.payload; + }, + setToken: (state, action: PayloadAction) => { localStorage.setItem( "token", JSON.stringify({ @@ -21,7 +24,6 @@ export const authSlice = createSlice({ refresh: action.payload.refresh, }) ); - state.user = action.payload; }, logout: (state) => { localStorage.clear(); @@ -32,5 +34,5 @@ export const authSlice = createSlice({ }); export const selectAuth = (state: RootState) => state.auth; -export const { setUser, logout } = authSlice.actions; +export const { setUser, setToken, logout } = authSlice.actions; export default authSlice.reducer; diff --git a/frontend/src/types/api.types.ts b/frontend/src/types/api.types.ts index a3a336f..7f1e433 100644 --- a/frontend/src/types/api.types.ts +++ b/frontend/src/types/api.types.ts @@ -114,9 +114,8 @@ interface Dependency { task_ids: number[]; } -interface Job { +export type Job = { id: number; - description: string; customer: string; due_date: string; @@ -141,12 +140,15 @@ interface Job { dependency_ids: number[]; tasks: Task[]; dependencies: Dependency[]; -} +}; -export type JobApiResponse = { - items: Job[]; +export type JobStatusResponse = { + id: number; + name: string; }; +export type JobTypeResonse = Partial; + //#region job api types // export type JobError = { // name: Array; @@ -196,19 +198,30 @@ export type JobApiResponse = { export type CreateJob = { name: string; - priority: Nullable; - due_date: Nullable; - customer: Nullable; - description: string; - note: string; - planned_start: string; - planned_end: string; + customer: string; + due_date: string; + external_id: string; + job_status_id: number; + job_type_id: number; + dependency_ids: number[]; + task_ids: number[]; + priority: number; }; export type UpdateJob = { // id: Pick; id: string; - data: Partial; + data: { + name: string; + customer: string; + due_date: string; + external_id: string; + job_status_id: number; + job_type_id: number; + dependency_ids: number[]; + task_ids: number[]; + priority: number; + }; }; // //#endregion