diff --git a/README.md b/README.md index 3f33515..47f847b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,18 @@ # Create React App example with TypeScript +## Demo + +[demo](https://aurochemicals.netlify.app/) + +### How to run +Open link in browser and allow insecure content from the browser site settings + +Enter Credentials: +username: panwar.arjunp@gmail.com +password: 12345 + +Design [Mockup](https://drive.google.com/file/d/1Q5noz5kTkKYhGGG5jupBBYl4ZdM9HA4U/view?usp=sharing) + ## How to use Download the example [or clone the repo](https://github.com/mui-org/material-ui): diff --git a/package.json b/package.json index fe09ae1..8d67e41 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "react": "latest", "react-chartjs-2": "^2.10.0", "react-dom": "latest", + "react-pdf": "^5.0.0", "react-redux": "^7.2.1", "react-router-dom": "^5.2.0", "react-scripts": "latest", @@ -47,5 +48,7 @@ "last 1 safari version" ] }, - "devDependencies": {} + "devDependencies": { + "@types/react-pdf": "^4.0.6" + } } diff --git a/public/favicon.ico b/public/favicon.ico index a11777c..07265ee 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/CustomDrawer.tsx b/src/CustomDrawer.tsx index 8a9c7e7..fc15803 100644 --- a/src/CustomDrawer.tsx +++ b/src/CustomDrawer.tsx @@ -13,6 +13,8 @@ import OrganizationIcon from "./assets/icons/OrganizationIcon"; import SettingsIcon from '@material-ui/icons/Settings'; import PersonIcon from '@material-ui/icons/Person'; import logo from 'assets/logo/logosmall.png' +import { useSelector } from 'react-redux'; +import { RootState } from 'app/rootReducer'; const drawerWidth = 295; @@ -133,6 +135,10 @@ const mappableRoutes: MappableRoutesDictionary = { path: '/', icon: }, + 'Contractor': { + path: '/contractor', + icon: + }, 'Invites': { path: '/invites', icon: @@ -151,9 +157,11 @@ const mappableRoutes: MappableRoutesDictionary = { }, { title: 'Check in points', path: '/checkinpoints' - }, { - title: 'organisations' - }] + }, + // { + // title: 'organisations' + // } + ] }, 'Reports': { path: '/reports', @@ -173,10 +181,12 @@ const mappableRoutes: MappableRoutesDictionary = { }, { title: 'Agreement', path: '/agreement' - }, { - title: 'Visitor\'s Form', - path: '/visitorsform' - }, { + }, + // { + // title: 'Visitor\'s Form', + // path: '/visitorsform' + // }, + { title: 'Notification', path: '/notification' }] @@ -192,6 +202,8 @@ const CustomDrawer: FunctionComponent = (props) => { sales: false } + const { roles } = useSelector((state: RootState) => state.auth) + const [open, setOpen] = useState(dropDownState) const handleClick = (name: string) => { @@ -215,7 +227,7 @@ const CustomDrawer: FunctionComponent = (props) => { - Company Logo + AUROCHEMICALS {/* */} @@ -260,7 +272,7 @@ const CustomDrawer: FunctionComponent = (props) => { ) : ( - {mappableRoutes[key].icon} diff --git a/src/api/Apis.tsx b/src/api/Apis.tsx index 8ff6675..026e55a 100644 --- a/src/api/Apis.tsx +++ b/src/api/Apis.tsx @@ -1,59 +1,62 @@ -import axios from 'axios' -import parseLink, { Links } from 'parse-link-header' -import { VisitorInfo } from 'features/Home/visitorSlice'; +import axios from "axios"; +import { VisitorInfo } from "features/Home/visitorSlice"; + +// export const serverUrl = "http://localhost:8000/"; + +export const serverUrl = process.env.REACT_APP_SERVER_URL || 'http://localhost:8000' // http://52.66.55.89:18446/' + +let user = sessionStorage.getItem('authUser'); + +if (!user) user = localStorage.getItem('authUser') + +if (user) { + JSON.parse(user) + //outhUser(JSON.parse(user)); + user = JSON.parse(user) +} else { + //@ts-ignore + user = { token: "" } +} +//@ts-ignore +const { token } = user export const apis = axios.create({ - baseURL: 'http://52.66.55.89:18446', - timeout: 5000, + baseURL: serverUrl, + params: { + //@ts-ignore + token: token || "" + }, + timeout: 10000, //headers: {'X-Custom-Header': 'foobar'} }); -interface CheckinModelOld { - name: string, - mobile: number, - email: string, - tomeet: string, - purpose: string, - gender: string, - noofvisitor: number, - company: string, - country: string, - organisation: string, - site: string, - vehicleno: string, - belongings: string, - idtype: string, - idnumber: string -} interface CheckinModel { - profilepic: any//"" - idcard: any//"" - signature: any//"" - name: any//"arjun" - mobile: any//"9769335758" - email: any//"arjunpanwar85@gmail.com" - tomeet: any//"arjunp" - purpose: any//"tomeet" - gender: any//"male" - visitorcount: any//"2" - company: any//"test" - country: any//"India" - organisation: any//"test" - site: any//"test" - vehicleno: any//"test" - belongings: any//"test" - idtype: any//"pancard" + profilepic: any; //"" + idcard: any; //"" + signature: any; //"" + name: any; //"arjun" + mobile: any; //"9769335758" + email: any; //"arjunpanwar85@gmail.com" + tomeet: any; //"arjunp" + purpose: any; //"tomeet" + gender: any; //"male" + visitorcount: any; //"2" + company: any; //"test" + country: any; //"India" + organisation: any; //"test" + site: any; //"test" + vehicleno: any; //"test" + belongings: any; //"test" + idtype: any; //"pancard" } interface UserModel { - username: any, - password: any, - name: any, - usertype: any + username: any; + password: any; + name: any; + usertype: any; } - - // export interface VisitorInfo { // avatar: any, // name: any, @@ -65,229 +68,391 @@ interface UserModel { // } export interface VisitorsResult { //pageLinks: Links | null - pageCount: number - visitors: VisitorInfo[] + pageCount: number; + visitors: VisitorInfo[]; } export async function checkin(model: CheckinModel) { - const url = `/product/reception/user/checkin` + const url = `/product/reception/user/checkin`; - const { data } = await apis.post(url, { data: model }) - return data + const { data } = await apis.post(url, { data: model }); + return data; } export async function login(model: UserModel) { - const url = `/product/login` + const url = `/product/login`; - const { data } = await apis.post(url) - return data + const { data } = await apis.post(url); + return data; } export async function register(model: UserModel) { - const url = `/product/acountDetail/register` + const url = `/product/acountDetail/register`; - const { data } = await apis.post(url) - return data + const { data } = await apis.post(url); + return data; } export async function data(model: any) { - const url = `/product/reception/user/data` - - const { data } = await apis.get(url) - return data + const url = `/product/reception/user/data`; + const { data } = await apis.get(url); + return data; } interface VisitorModel { - "belongings": any//"belongings", - "company": any//"company", - "country": any//"country", - "email": any//"arjunpanwar85@gmail.com", - "gender": any//"gender", - "idnumber": any//"idtype", - "idtype": any//"idtype", - "intime": any//"2020-09-10 00:29:31", - "mobile": any//9769335758, - "name": any//"arjun", - "noofvisitor": any// 4, - "organisation": any//"organisation", - "purpose": any//"to meet", - "site": any//"site", - "tomeet": any//"Arjunp", - "vehicleno": any//"vehicleno" + belongings: any; //"belongings", + company: any; //"company", + country: any; //"country", + email: any; //"arjunpanwar85@gmail.com", + gender: any; //"gender", + idnumber: any; //"idtype", + idtype: any; //"idtype", + intime: any; //"2020-09-10 00:29:31", + mobile: any; //9769335758, + name: any; //"arjun", + noofvisitor: any; // 4, + organisation: any; //"organisation", + purpose: any; //"to meet", + site: any; //"site", + tomeet: any; //"Arjunp", + vehicleno: any; //"vehicleno" } -export async function getVisitorData(page:number=0,count:number=10) { - const url = `/product/reception/checkin/user/data?page=${page}&count=${count}` +export async function getVisitorData( + page: number = 0, + count: number = 10, + visitor: String = "", + purpose: String = "", + site: String = "" +) { + const url = `/product/reception/checkin/user/data?page=${page}&count=${count}&visitor=${visitor}&purpose=${purpose}&site=${site}`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); // debugger return { //pageLinks: '', pageCount: data.totalCount, - visitors: data.data - } + visitors: data.data, + }; // debugger } -export async function getVisitorInfo() { - const url = `` - - //const { data } = await apis.post(url) - const sample = { - avatar: '', - name: 'Vijaya Tondon from API', - mobileNo: 9754821630, - personToMeet: 'Ramesh Chawla', - purpose: 'Meeting', - inTime: '11:30 am', - outTime: '2:30 pm', - } - let data = [] - for (let i = 0; i < 10; i++) { - let copy: any = sample - - data.push(copy) - } +export async function getInOfficeVisitorData( + page: number = 0, + count: number = 10, + visitor: String = "", + purpose: String = "", + site: String = "" +) { + const url = `/product/reception/checkin/in/user/data?page=${page}&count=${count}&visitor=${visitor}&purpose=${purpose}&site=${site}`; + + const { data } = await apis.get(url); + // debugger return { //pageLinks: '', - pageCount: 1, - visitors: data - } + pageCount: data.totalCount, + visitors: data.data, + }; + // debugger } export async function getHomeStats() { - const url = `/product/stats/data?page=0&count=10` + const url = `/product/stats/data?page=0&count=10`; - const { data } = await apis.get(url) - return data + const { data } = await apis.get(url); + return data; } -export async function getInvitesData(page:number=0,count:number=10) { - const url = `/product/reception/invite/user/data?page=${page}&count=${count}` +export async function getInvitesData( + page: number = 0, + count: number = 10, + visitor: String = "", + purpose: String = "", + site: String = "" +) { + const url = `/product/reception/invite/user/data?page=${page}&count=${count}&visitor=${visitor}&purpose=${purpose}&site=${site}`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); return { //pageLinks: '', pageCount: data.totalCount, - invites: data.data - } + invites: data.data, + }; +} + +export async function getInOfficeInviteData( + page: number = 0, + count: number = 10 +) { + const url = `/product/reception/checkin/in/user/data?page=${page}&count=${count}`; + const { data } = await apis.get(url); + // debugger + return { + //pageLinks: '', + pageCount: data.totalCount, + invites: data.data, + }; + // debugger } -export async function getEmployeesData(page:number=0,count:number=10) { - const url = `/product/reception/checkin/user/data?page=${page}&count=${count}` +export async function getEmployeesData( + page: number = 0, + count: number = 10, + filter: string = "" +) { + const url = `/product/employee/data?page=${page}&count=${count}&keyword=${filter}`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); return { //pageLinks: '', pageCount: data.totalCount, - employees: data.data - } - + employees: data.data, + }; } -export async function getSitesData(page:number=0,count:number=10) { - const url = `/product/site/data?page=${page}&count=${count}` +export async function getSitesData(page: number = 0, count: number = 10) { + const url = `/product/site/data?page=${page}&count=${count}`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); return { //pageLinks: '', pageCount: data.totalCount, - sites: data.data.map((item:any,i:any)=>({...item,site_id:i})) - } - + sites: data.data.map((item: any, i: any) => ({ ...item, site_id: i })), + }; } -export async function getCheckInPointsData(page:number=0,count:number=10) { - const url = `/product/checkinpoint/data?page=${page}&count=${count}` +export async function getCheckInPointsData( + page: number = 0, + count: number = 10 +) { + const url = `/product/checkinpoint/data?page=${page}&count=${count}`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); return { //pageLinks: '', pageCount: data.totalCount, - checkInPoints: data.data.map((item:any,i:any)=>({...item,checkinpoint_id:i})) - } - + checkInPoints: data.data.map((item: any, i: any) => ({ + ...item, + checkinpoint_id: i, + })), + }; } -export async function getDevicesData(page:number=0,count:number=10) { - const url = `/product/device/data?page=${page}&count=${count}` +export async function getDevicesData(page: number = 0, count: number = 10) { + const url = `/product/device/data?page=${page}&count=${count}`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); // debugger return { //pageLinks: '', pageCount: data.totalCount || 20, - devices: data.data - } + devices: data.data, + }; +} + +export async function getPurpose(page: number = 0, count: number = 10) { + const url = `/product/reception/meeting/purpose/data?page=${page}&count=${count}`; + const { data } = await apis.get(url); + // debugger + return { + //pageLinks: '', + pageCount: data.totalCount || 20, + purpose: data.data, + }; } export async function getUsersData() { - const url = `/product/device/data?page=0&count=10` + const url = `/product/device/data?page=0&count=10`; - const { data } = await apis.get(url) + const { data } = await apis.get(url); // debugger return { //pageLinks: '', pageCount: 1, - users: data.data - } - + users: data.data, + }; } export async function checkout(id: any) { - await apis.post('/product/reception/user/checkout', JSON.stringify({ - "checkin_id": id - }), { - headers: { - "Cache-Control": "no-cache", - 'Content-Type': 'application/json' + await apis.post( + "/product/reception/user/checkout", + JSON.stringify({ + checkin_id: id, + }), + { + headers: { + "Cache-Control": "no-cache", + "Content-Type": "application/json", + }, } - }) + ); } export async function createInvite(json: string) { - return await apis.post('/product/reception/user/invite', json, { + return await apis.post("/product/reception/user/invite", json, { headers: { "Content-Type": "application/json", // "Content-Length": 2617 }, - }) + }); } export async function createDevice(json: string) { - return await apis.post('/product/acountDetail/device/register', json, { + return await apis.post("/product/acountDetail/device/register", json, { headers: { "Content-Type": "application/json", // "Content-Length": 2617 }, - }) + }); +} +export async function createEmployee(formData: any) { + return await apis.post("/product/employee/register", formData, { + headers: { + "Content-Type": "multipart/form-data", + // "Content-Length": 2617 + }, + }); +} +export async function createSite(json: string) { + return await apis.post("/product/register/site", json, { + headers: { + "Content-Type": "application/json", + // "Content-Length": 2617 + }, + }); +} +export async function createCheckInPoint(json: string) { + return await apis.post("/product/register/checkinpoint", json, { + headers: { + "Content-Type": "application/json", + // "Content-Length": 2617 + }, + }); } export async function signIn(username: string, password: string) { - return await apis.post('/product/login', JSON.stringify({ - "username": username, - "password": password - }), { - headers: { - 'Content-type': 'application/json' + return await apis.post( + "/product/login", + JSON.stringify({ + username: username, + password: password, + }), + { + headers: { + "Content-type": "application/json", + }, } - }) + ); } // panwar.arjunp@gmail.com 12345 -export async function signUp(username: string, password: string, name: string, userType: string) { - return await apis.post('/product/accountDetail/register', +export async function signUp( + username: string, + password: string, + name: string, + userType: string +) { + return await apis.post( + "/product/accountDetail/register", JSON.stringify({ - "username": username, - "password": password, - "name": name, - "usertype": userType - }), { - headers: { - 'Content-type': 'application/json' + username: username, + password: password, + name: name, + usertype: userType, + }), + { + headers: { + "Content-type": "application/json", + }, } - }) -} \ No newline at end of file + ); +} + +export async function getVisitorConfigData() { + //const url = `/product/reception/checkin/user/data?page=${page}&count=${count}&visitor=${visitor}&purpose=${purpose}&site=${site}` + + //const { data } = await apis.get(url) + // debugger + const data = { + answer1: true, + answer2: true, + answer3: true, + answer4: true, + answer5: true, + belongings: true, + checkin_id: true, + city: true, + company: true, + country: true, + email: true, + gender: true, + idCardImagePath: true, + idtype: true, + intime: true, + mobile: true, + name: true, + ndastatus: true, + noofvisitor: true, + organisation: true, + outime: true, + policycheckstatus: true, + profilePicPath: true, + purpose: true, + signaturePath: true, + site: true, + tomeet: true, + usertype: true, + vehicleno: true, + }; + return { + //pageLinks: '', + pageCount: 10, //data.totalCount, + //@ts-ignore + visitorConfigs: Object.keys(data).map((i: string) => ({ + key: i, + // value: data[i], + })), //data.data + }; + // debugger +} + +export async function getContractorData( + page: number = 0, + count: number = 10, + contractor: String = "", + purpose: String = "", + site: String = "" +) { + const url = `/product/reception/checkin/user/data?page=${page}&count=${count}&visitor=${contractor}&purpose=${purpose}&site=${site}`; + + const { data } = await apis.get(url); + // debugger + return { + //pageLinks: '', + pageCount: data.totalCount, + contractors: data.data, + }; + // debugger +} + +export async function getInOfficeContractorData( + page: number = 0, + count: number = 10, + contractor: String = "", + purpose: String = "", + site: String = "" +) { + const url = `/product/reception/checkin/in/user/data?page=${page}&count=${count}`; + + const { data } = await apis.get(url); + // debugger + return { + //pageLinks: '', + pageCount: data.totalCount, + contractors: data.data, + }; + // debugger +} diff --git a/src/app/App.tsx b/src/app/App.tsx index 58ce150..543b4a7 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,4 +1,4 @@ -import { Backdrop, Box, CircularProgress, createStyles, Grid, Theme } from "@material-ui/core" +import { Backdrop, Box, CircularProgress, createStyles, Grid, Snackbar, Theme } from "@material-ui/core" import Container from '@material-ui/core/Container' import { makeStyles } from "@material-ui/core/styles" import { AuthRoute } from 'app/AuthRoute' @@ -8,7 +8,7 @@ import SignIn from 'features/auth/SignIn' import SignUp from 'features/auth/SignUp' import EmployeesView from "features/Employees/EmployeesView" import HomeView from "features/Home/HomeView" -import VisitorDetailsView from "features/Home/VisitorDetailsView" +import VisitorDetailsView from "features/Home/VisitorDetailsView1" import InviteForm from "features/Invites/InviteForm" import InviteView from "features/Invites/InviteView" import CheckInPointsView from "features/SalesAndOrganisation/CheckInPointsView" @@ -17,14 +17,20 @@ import AgreementView from "features/Settings/AgreementView" import DeviceForm from "features/Settings/DeviceForm" import DevicesView from "features/Settings/DevicesView" import UserManagementView from "features/UserManagement/UserManagementView" -import React from 'react' +import React, { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { Redirect, Route, Switch } from 'react-router-dom' import { RootState } from './rootReducer' -import {outhUser,setAuthUser} from 'features/auth/AuthSlice' +import { outhUser, setAuthUser } from 'features/auth/AuthSlice' import './styles.css' import VisitorsForm from "features/Settings/VisitorsForm" import Notification from "features/Settings/Notification" +import SiteForm from "features/SalesAndOrganisation/SiteForm" +import CheckInPointForm from "features/SalesAndOrganisation/CheckInPointForm" +import { fetchVisitorConfigs } from "features/Settings/visitorConfigSlice" +import ContractorView from "features/contractor/contractorView" +import EmployeeForm from "features/Employees/EmployeeForm" +import { startSnackbar, stopSnackbar } from "./SnackbarSlice" const useStyles = makeStyles((theme: Theme) => @@ -62,19 +68,20 @@ export default function App() { const dispatch = useDispatch() - const {isLoggedIn} = useSelector((state: RootState) => state.auth) + const { isLoggedIn } = useSelector((state: RootState) => state.auth) const { mask } = useSelector((state: RootState) => state.backdrop) + const { open, vertical, horizontal, message } = useSelector((state: RootState) => state.snackbar) if (!isLoggedIn) { // debugger //localStorage.loginRedirect = rest.location.pathname const user = sessionStorage.getItem('authUser'); - if(user){ + if (user) { JSON.parse(user) //outhUser(JSON.parse(user)); dispatch(setAuthUser(JSON.parse(user))) - }else{ + } else { //return } } @@ -83,37 +90,48 @@ export default function App() { + dispatch(stopSnackbar())} + message={message} + key={vertical + horizontal} + /> {/* */} - {/* */} - {/* */} - - {/* */} - {/* */} - {/* */} - - - - - - - - - - - - - - - - - - - - - - - {/* */} + {/* */} + {/* */} + + {/* */} + {/* */} + {/* */} + + + + + + + + + + + + + + + + + + + + + + + + + + {/* */} {/* */} @@ -123,14 +141,17 @@ export default function App() { - + + + + @@ -140,9 +161,13 @@ export default function App() { + {/* */} + useEffect(() => { + dispatch(fetchVisitorConfigs()) + }, [dispatch]) return isLoggedIn ? Routes : AuthRoutes } diff --git a/src/app/AuthRoute.tsx b/src/app/AuthRoute.tsx index bfbb0c7..49e7361 100644 --- a/src/app/AuthRoute.tsx +++ b/src/app/AuthRoute.tsx @@ -1,35 +1,35 @@ -import * as React from 'react' -import { useSelector } from 'react-redux' -import { Redirect, Route, RouteComponentProps, RouteProps } from 'react-router-dom' -import { RootState } from './rootReducer' +import * as React from "react"; +import { useSelector } from "react-redux"; +import { + Redirect, + Route, + RouteComponentProps, + RouteProps, +} from "react-router-dom"; +import { RootState } from "./rootReducer"; interface IRouteProps { - component?: React.FunctionComponent - render?: () => React.FunctionComponent + component?: React.FunctionComponent; + render?: () => React.FunctionComponent; } -type Props = IRouteProps & RouteComponentProps | RouteProps +type Props = (IRouteProps & RouteComponentProps) | RouteProps; export const AuthRoute: React.FC = (props: Props) => { - const { - component: ComponentToRender, - render: RenderComponent, - ...rest - } = props + const { + component: ComponentToRender, + render: RenderComponent, + ...rest + } = props; - const { isLoggedIn } = useSelector((state: RootState) => state.auth) + const { isLoggedIn } = useSelector((state: RootState) => state.auth); - if (!isLoggedIn) { - localStorage.loginRedirect = rest.location.pathname - return - } - if (!ComponentToRender && RenderComponent) { - return - } - return ( - - ) -} + if (!isLoggedIn) { + localStorage.loginRedirect = rest.location.pathname; + return ; + } + if (!ComponentToRender && RenderComponent) { + return ; + } + return ; +}; diff --git a/src/app/SnackbarSlice.ts b/src/app/SnackbarSlice.ts new file mode 100644 index 0000000..ca18654 --- /dev/null +++ b/src/app/SnackbarSlice.ts @@ -0,0 +1,37 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +interface SnackbarState { + open: boolean, + message: string, + vertical: string, + horizontal: string, +} + +const snackbarInitialState: SnackbarState = { + open: false, + message: '', + vertical: 'bottom', + horizontal: 'center', +} + +const SnackbarSlice = createSlice({ + name: 'snackbar', + initialState: snackbarInitialState, + reducers: { + startSnackbar(state: SnackbarState, { payload }: PayloadAction) { + const {message} = payload + state.open = true + state.message = message + }, + stopSnackbar(state: SnackbarState) { + state.open = false + } + } +}) + +export const { + startSnackbar, + stopSnackbar +} = SnackbarSlice.actions + +export default SnackbarSlice.reducer diff --git a/src/app/rolesConfig.ts b/src/app/rolesConfig.ts new file mode 100644 index 0000000..bcf1fa1 --- /dev/null +++ b/src/app/rolesConfig.ts @@ -0,0 +1,34 @@ + +export const roles = { + + admin:{ + Home:true, + Invites:true, + Contractor:false, + Employees:true, + Master:true, + Reports:true, + 'User Management':true, + Settings:true + }, + hr:{ + Home:false, + Invites:true, + Contractor:false, + Employees:true, + Master:false, + Reports:true, + 'User Management':false, + Settings:false + }, + reception:{ + Home:true, + Invites:true, + Contractor: false, + Employees:true, + Master:false, + Reports:true, + 'User Management':false, + Settings:false + } +} \ No newline at end of file diff --git a/src/app/rootReducer.ts b/src/app/rootReducer.ts index edc2bc9..80e2fa0 100644 --- a/src/app/rootReducer.ts +++ b/src/app/rootReducer.ts @@ -3,6 +3,7 @@ import { combineReducers } from '@reduxjs/toolkit' import homeReducer from 'features/Home/homeSlice' import backDropReducer from 'app/BackdropSlice' +import snackBarReducer from 'app/SnackbarSlice' import visitorReducer from 'features/Home/visitorSlice' import inviteReducer from 'features/Invites/inviteSlice' import employeeReducer from 'features/Employees/employeeSlice' @@ -12,9 +13,12 @@ import userReducer from 'features/UserManagement/userSlice' import authReducer from 'features/auth/AuthSlice' import notificationReducer from 'features/Settings/NotificationSlice' import checkInPointReducer from 'features/SalesAndOrganisation/checkInPointSlice' +import visitorConfigReducer from 'features/Settings/visitorConfigSlice' +import contractorReducer from 'features/contractor/contractorSlice' const rootReducer = combineReducers({ backdrop: backDropReducer, + snackbar: snackBarReducer, home: homeReducer, visitors: visitorReducer, invites: inviteReducer, @@ -24,7 +28,9 @@ const rootReducer = combineReducers({ users: userReducer, auth: authReducer, notifications:notificationReducer, - checkinpoints:checkInPointReducer + checkinpoints:checkInPointReducer, + visitorConfig: visitorConfigReducer, + contractors: contractorReducer }) export type RootState = ReturnType diff --git a/src/app/styles.css b/src/app/styles.css index d2991af..06d0ad2 100644 --- a/src/app/styles.css +++ b/src/app/styles.css @@ -19,4 +19,10 @@ body { * { margin: 0; padding: 0; +} + +#date-picker-inline { + padding: 12px; + font-size: 12px; + border-radius: 10px; } \ No newline at end of file diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 3f2ee69..92c5970 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,32 +1,31 @@ import { ExtendButtonBase, Theme, withStyles } from "@material-ui/core"; -import Button, { ButtonTypeMap } from '@material-ui/core/Button'; -import React, { FunctionComponent } from 'react'; +import Button, { ButtonTypeMap } from "@material-ui/core/Button"; +import React, { FunctionComponent } from "react"; interface OwnProps extends React.AllHTMLAttributes { - fullWidth?: any - variant?: string + fullWidth?: any; + variant?: string; } type Props = OwnProps; const GradientButton = withStyles((theme: Theme) => ({ - root: { - backgroundImage: 'linear-gradient(to right, #2C578A, #20849C)', - color: theme.palette.common.white, - fontSize: 15, - fontWeight: 'bold', - padding: theme.spacing(1.5, 10), - borderRadius: 50, - height: '56px' - } -}))(Button) + root: { + backgroundImage: "linear-gradient(to right, #2C578A, #20849C)", + color: theme.palette.common.white, + fontSize: 15, + fontWeight: "bold", + padding: theme.spacing(1.5, 10), + borderRadius: 50, + height: "56px", + }, +}))(Button); const CustomButton: FunctionComponent = (props) => { - - return ( + return ( // @ts-ignore - - ); + + ); }; export default CustomButton; diff --git a/src/components/CheckBoxComponent.tsx b/src/components/CheckBoxComponent.tsx index 66063d8..abe0d64 100644 --- a/src/components/CheckBoxComponent.tsx +++ b/src/components/CheckBoxComponent.tsx @@ -11,6 +11,6 @@ type CheckBoxComponentProps = { export const CheckBoxComponent: FunctionComponent = ({isChecked, handleChange, title}) => } + control={} label={title} /> \ No newline at end of file diff --git a/src/components/CustomAutoComplete.tsx b/src/components/CustomAutoComplete.tsx new file mode 100644 index 0000000..425ae44 --- /dev/null +++ b/src/components/CustomAutoComplete.tsx @@ -0,0 +1,99 @@ +import classes from '*.module.css'; +import { createStyles, makeStyles, Theme } from '@material-ui/core'; +import { Autocomplete, createFilterOptions } from '@material-ui/lab'; +import { RootState } from 'app/rootReducer'; +import * as React from 'react' +import { useDispatch, useSelector } from 'react-redux'; +import TextInput from './TextInput'; + +interface Props { + +} + +const useStyles = makeStyles((theme: Theme) => createStyles({ + inputRoot: { + paddingTop: '0px !important', + paddingBottom: '0px !important', + paddingLeft: '0px !important', + // flexWrap: 'wrap-reverse' + }, + labelRoot: { + color: theme.palette.text.primary, + fontSize: '12px' + } +})) + +const filter = createFilterOptions(); + +export const CustomAutoComplete: React.FC = (props) => { + + const classes = useStyles() + + const { value, onChange, options, label, name } = props + + const [ value1, setValue1] = React.useState(options.find((o:any)=>o===value)); + + return ( + { + setValue1(newValue); + }} + inputValue={value} + onInputChange={(event, newInputValue) => { + onChange(newInputValue); + }} + clearOnBlur + selectOnFocus + handleHomeEndKeys + filterOptions={(options: any, params: any) => { + const filtered = filter(options, params); + // Suggest the creation of a new value + if (params.inputValue !== '') { + filtered.push({ + inputValue: params.inputValue, + title: `Add "${params.inputValue}"`, + }); + } + return filtered; + }} + getOptionLabel={(option: any) => { + // Value selected with enter, right from the input + if (typeof option === 'string') { + return option; + } + // Add "xxx" option created dynamically + if (option.inputValue) { + return option.inputValue; + } + // Regular option + return option.title; + }} + options={options} + id="custom-input-demo" + forcePopupIcon={false} + fullWidth={true} + disableClearable={true} + classes={{ + inputRoot: classes.inputRoot + }} + + renderInput={(params) => ( + + + )} + /> + ); +} \ No newline at end of file diff --git a/src/components/DateTimeInput.tsx b/src/components/DateTimeInput.tsx index a37db55..dd1f62f 100644 --- a/src/components/DateTimeInput.tsx +++ b/src/components/DateTimeInput.tsx @@ -17,28 +17,11 @@ const useStyles = makeStyles(() => createStyles({ })) -const StyledTextInput = withStyles({ - '& .MuiInputBase-input.MuiInput-input.MuiInputBase-inputAdornedEnd': { - paddingTop: '8.5px', - paddingBottom: '8.5px', - } -})(TextInput) - -const StyledDatePicker = withStyles({ - '& .MuiInput-underline:before': { - borderBottom: 'none' - }, - '& .MuiInputBase-input.MuiInput-input.MuiInputBase-inputAdornedEnd': { - paddingTop: '8.5px', - paddingBottom: '8.5px', - } -})(KeyboardDateTimePicker) - const DateTimeInput: FunctionComponent = (props) => { return ( - diff --git a/src/components/SearchInput.tsx b/src/components/SearchInput.tsx index e019c82..40e316e 100644 --- a/src/components/SearchInput.tsx +++ b/src/components/SearchInput.tsx @@ -1,5 +1,5 @@ import React, { FunctionComponent } from 'react'; -import {Box, createStyles, fade, InputBase, Paper, Theme} from "@material-ui/core"; +import {Box, createStyles, fade, InputBase, InputBaseProps, Paper, Theme} from "@material-ui/core"; import SearchIcon from "@material-ui/icons/Search"; import {makeStyles} from "@material-ui/core/styles"; @@ -9,7 +9,7 @@ interface OwnProps extends React.HTMLAttributes { height?: number } -type Props = OwnProps; +type Props = OwnProps & InputBaseProps; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -76,6 +76,8 @@ const SearchInput: FunctionComponent = (props) => { { value: string; padding?: number; menuOptions?: IMenuOptions[]; + width?: number; + height?: number; } type Props = OwnProps; -const useStyles = makeStyles((theme: Theme) => createStyles({ +const useStyles = makeStyles((theme: Theme) => ({ + root: { + backgroundColor: '#fff', + fontSize: '11.25px', + position: 'absolute', + //top: 15, + //left: 15, + // height:25, + color: theme.palette.text.primary, + }, inputContainer: { // padding: (props: Props) => props.padding ? props.padding : 15, marginRight: 20, - '& .MuiButtonBase-root.MuiListItem-root.MuiMenuItem-root.Mui-selected.MuiMenuItem-gutters.MuiListItem-gutters.MuiListItem-button.Mui-selected': { - backgroundColor: '#fff', - }, - '& .MuiInputBase-root.MuiInput-root, & .MuiSelect-select.MuiSelect-select, & .MuiSelect-nativeInput': { - height: 'inherit' - }, - '& .MuiSelect-select.MuiSelect-select': { - padding: 0, - borderRadius: theme.shape.borderRadius - 5, - }, - '& .MuiListItem-root.Mui-selected, & .MuiListItem-root.Mui-selected:hover': { - backgroundColor: 'white !important', - padding: 0 - }, + // '& .MuiButtonBase-root.MuiListItem-root.MuiMenuItem-root.Mui-selected.MuiMenuItem-gutters.MuiListItem-gutters.MuiListItem-button.Mui-selected': { + // backgroundColor: '#fff', + // }, + // '& .MuiInputBase-root.MuiInput-root, & .MuiSelect-select.MuiSelect-select, & .MuiSelect-nativeInput': { + // height: 'inherit' + // }, + // '& .MuiSelect-select.MuiSelect-select': { + // padding: 0, + // borderRadius: theme.shape.borderRadius - 5, + // }, + // '& .MuiListItem-root.Mui-selected, & .MuiListItem-root.Mui-selected:hover': { + // backgroundColor: 'white !important', + // padding: 0 + // }, // '& .makeStyles-inputRoot-46': { // backgroundColor: theme.palette.common.white, // '&:hover': { // backgroundColor: theme.palette.common.white, // }, // }, - '& .MuiSelect-root, & .MuiSelect-select, & .MuiSelect-selectMenu, & .MuiInputBase-input, & .MuiInput-input': { - opacity: 1, - color: theme.palette.text.primary, + // '& .MuiSelect-root, & .MuiSelect-select, & .MuiSelect-selectMenu, & .MuiInputBase-input, & .MuiInput-input': { + // opacity: 1, + // color: theme.palette.text.primary, + // }, + // '& .MuiFormLabel-root, & .MuiInputLabel-root, & .MuiInputLabel-animated': { + // fontSize: '11.25px', + // position: 'absolute', + // top: '15px', + // left: '15px', + // color: theme.palette.text.primary, + // } + }, + nativeInput: { + fontSize: 11.25, + position: 'absolute', + top: 15, + left: 15, + alignItems: 'center', + // paddingTop: 25, + textAlign: "justify", + color: theme.palette.text.primary, + borderRadius: theme.shape.borderRadius - 5, + }, + selectMenu: { + position: 'relative', + borderRadius: theme.shape.borderRadius - 5, + backgroundColor: theme.palette.common.white, + '&:hover': { + backgroundColor: theme.palette.common.white, }, - '& .MuiFormLabel-root, & .MuiInputLabel-root, & .MuiInputLabel-animated': { - fontSize: '11.25px', - position: 'absolute', - top: '15px', - left: '15px', - color: theme.palette.text.primary, - } + width: 135, }, select: { + //padding: 0, + //borderRadius: theme.shape.borderRadius - 5, position: 'relative', + textAlign: 'center', borderRadius: theme.shape.borderRadius - 5, backgroundColor: theme.palette.common.white, '&:hover': { backgroundColor: theme.palette.common.white, }, - width: '135px', - height: '40px', - // padding: '12px' + '&:focus': { + backgroundColor: theme.palette.common.white, + borderRadius: theme.shape.borderRadius - 5, + }, + width: (props: any) => props.width ? `${props.width}px` : 135, + // height: (props: any) => props.height ? `${props.height}px` : 38, + lineHeight: 2.5, + //height: 40, + //paddingTop: 12, '& .MuiSvgIcon-root': { position: 'absolute', top: '7px', @@ -79,39 +119,47 @@ const useStyles = makeStyles((theme: Theme) => createStyles({ // backgroundColor: theme.palette.common.white, // }, }, - menuItem: { + +})) + +const useMenuStyles = makeStyles((theme: Theme) => createStyles({ + root: { backgroundColor: theme.palette.common.white, + padding: theme.spacing(0.5, 1), + fontSize: '11.25px', }, - menuPapaer: { + selected: { backgroundColor: theme.palette.common.white, - '& .MuiListItem-root.Mui-selected, & .MuiListItem-root.Mui-selected:hover': { - backgroundColor: 'white !important', - padding: theme.spacing(0.5, 1) - }, - }, - menuRoot: { - // backgroundColor: theme.palette.common.white, + padding: theme.spacing(0.5, 1), + fontSize: '11.25px', }, -})) + +} +)) const SelectInput: FunctionComponent = (props) => { const classes = useStyles(props) + const menuClasses = useMenuStyles() return (
-
- + {/* {props.value} + }}>{props.value} */}
diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx new file mode 100644 index 0000000..76ace78 --- /dev/null +++ b/src/components/Switch.tsx @@ -0,0 +1,145 @@ +import React from 'react'; +import { withStyles, Theme, createStyles } from '@material-ui/core/styles'; +import { purple } from '@material-ui/core/colors'; +import FormGroup from '@material-ui/core/FormGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Switch, { SwitchClassKey, SwitchProps } from '@material-ui/core/Switch'; +import Grid from '@material-ui/core/Grid'; +import Typography from '@material-ui/core/Typography'; + +interface Styles extends Partial> { + focusVisible?: string; +} + +interface Props extends SwitchProps { + classes: Styles; + lable?:String; +} + +const PurpleSwitch = withStyles({ + switchBase: { + color: purple[300], + '&$checked': { + color: purple[500], + }, + '&$checked + $track': { + backgroundColor: purple[500], + }, + }, + checked: {}, + track: {}, +})(Switch); + +const IOSSwitch = withStyles((theme: Theme) => + createStyles({ + root: { + width: 42, + height: 26, + padding: 0, + margin: theme.spacing(1), + }, + switchBase: { + padding: 1, + '&$checked': { + transform: 'translateX(16px)', + color: theme.palette.common.white, + '& + $track': { + backgroundColor: '#52d869', + opacity: 1, + border: 'none', + }, + }, + '&$focusVisible $thumb': { + color: '#52d869', + border: '6px solid #fff', + }, + }, + thumb: { + width: 24, + height: 24, + }, + track: { + borderRadius: 26 / 2, + border: `1px solid ${theme.palette.grey[400]}`, + backgroundColor: theme.palette.grey[50], + opacity: 1, + transition: theme.transitions.create(['background-color', 'border']), + }, + checked: {}, + focusVisible: {}, + }), +)(({ classes, ...props }: Props) => { + return ( + + ); +}); + +const AntSwitch = withStyles((theme: Theme) => + createStyles({ + root: { + width: 28, + height: 16, + padding: 0, + display: 'flex', + }, + switchBase: { + padding: 2, + color: theme.palette.grey[500], + '&$checked': { + transform: 'translateX(12px)', + color: theme.palette.common.white, + '& + $track': { + opacity: 1, + backgroundColor: theme.palette.primary.main, + borderColor: theme.palette.primary.main, + }, + }, + }, + thumb: { + width: 12, + height: 12, + boxShadow: 'none', + }, + track: { + border: `1px solid ${theme.palette.grey[500]}`, + borderRadius: 16 / 2, + opacity: 1, + backgroundColor: theme.palette.common.white, + }, + checked: {}, + }), +)(Switch); +//@ts-ignore +export default function CustomizedSwitch({label,checked,onChange,style}) { + const [state, setState] = React.useState({ + checkedA: true, + checkedB: true, + checkedC: true, + }); + + const handleChange1 = (event: React.ChangeEvent) => { + setState({ ...state, [event.target.name]: event.target.checked }); + }; + + return ( + + } + label={label} + labelPlacement="end" + /> + + ); +} diff --git a/src/components/TableWrapper.tsx b/src/components/TableWrapper.tsx index e3df8a3..d54635d 100644 --- a/src/components/TableWrapper.tsx +++ b/src/components/TableWrapper.tsx @@ -1,470 +1,542 @@ -import React, { FunctionComponent, useState } from 'react'; +import React, { FunctionComponent, useState } from "react"; import { - Box, - Button, - createStyles, - IconButton, - Menu, - MenuItem, - MenuProps, - Table, - TableBody, - TableCell, - TableContainer, - TableFooter, - TableHead, - TablePagination, - TableRow, - TableSortLabel, - Theme, - withStyles + Box, + Button, + createStyles, + IconButton, + Menu, + MenuItem, + MenuProps, + Table, + TableBody, + TableCell, + TableContainer, + TableFooter, + TableHead, + TablePagination, + TableRow, + TableSortLabel, + Theme, + withStyles, } from "@material-ui/core"; import { makeStyles, useTheme } from "@material-ui/core/styles"; import { - FirstPage as FirstPageIcon, - KeyboardArrowLeft, - KeyboardArrowRight, - LastPage as LastPageIcon + FirstPage as FirstPageIcon, + KeyboardArrowLeft, + KeyboardArrowRight, + LastPage as LastPageIcon, } from "@material-ui/icons"; -import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; +import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown"; import MoreHorizIcon from "@material-ui/icons/MoreHoriz"; -import { Skeleton } from '@material-ui/lab'; +import { Skeleton } from "@material-ui/lab"; interface IRowProps { - [id: string]: any; + [id: string]: any; } interface IMenuItemProps { - path?: string | ((id: any) => any); - title: string; - onClick?: () => any; - item: (id: any) => JSX.Element + path?: string | ((id: any) => any); + title: string; + onClick?: () => any; + item: (id: any) => JSX.Element; } interface ITableCellProps { - padding?: number; + padding?: number; } interface IColumnsConfig { - id: any, - label: any, - sequence?: number, - isSort?: boolean, - isFilterable?: boolean + id: any; + label: any; + sequence?: number; + isSort?: boolean; + isFilterable?: boolean; } interface IConfigObject { - columns: IColumnsConfig[]; - data: any[]; - menuOptions?: any[]; - cellOptions?: ITableCellProps; - isLoading?: Boolean; - pagination?: Boolean; - pageChange?: Function; - totalCount?: number + columns: IColumnsConfig[]; + data: any[]; + menuOptions?: any[]; + cellOptions?: ITableCellProps; + isLoading?: Boolean; + pagination?: Boolean; + pageChange?: Function; + totalCount?: number; } interface OwnProps extends React.HTMLAttributes { - config: IConfigObject; + config: IConfigObject; } const useStyles1 = makeStyles((theme: Theme) => - createStyles({ - root: { - flexShrink: 0, - marginLeft: theme.spacing(2.5), - }, - }), + createStyles({ + root: { + flexShrink: 0, + marginLeft: theme.spacing(2.5), + }, + }) ); function TablePaginationActions(props: TablePaginationActionsProps) { - const classes = useStyles1(); - const theme = useTheme(); - const { count, page, rowsPerPage, onChangePage } = props; - - const handleFirstPageButtonClick = (event: React.MouseEvent) => { - onChangePage(event, 0); - }; - - const handleBackButtonClick = (event: React.MouseEvent) => { - onChangePage(event, page - 1); - }; - - const handleNextButtonClick = (event: React.MouseEvent) => { - onChangePage(event, page + 1); - }; - - const handleLastPageButtonClick = (event: React.MouseEvent) => { - onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)); - }; - - return ( -
- - {theme.direction === 'rtl' ? : } - - - {theme.direction === 'rtl' ? : } - - = Math.ceil(count / rowsPerPage) - 1} - aria-label="next page" - > - {theme.direction === 'rtl' ? : } - - = Math.ceil(count / rowsPerPage) - 1} - aria-label="last page" - > - {theme.direction === 'rtl' ? : } - -
- ); + const classes = useStyles1(); + const theme = useTheme(); + const { count, page, rowsPerPage, onChangePage } = props; + + const handleFirstPageButtonClick = ( + event: React.MouseEvent + ) => { + onChangePage(event, 0); + }; + + const handleBackButtonClick = ( + event: React.MouseEvent + ) => { + onChangePage(event, page - 1); + }; + + const handleNextButtonClick = ( + event: React.MouseEvent + ) => { + onChangePage(event, page + 1); + }; + + const handleLastPageButtonClick = ( + event: React.MouseEvent + ) => { + onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)); + }; + + return ( +
+ + {theme.direction === "rtl" ? : } + + + {theme.direction === "rtl" ? ( + + ) : ( + + )} + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="next page" + > + {theme.direction === "rtl" ? ( + + ) : ( + + )} + + = Math.ceil(count / rowsPerPage) - 1} + aria-label="last page" + > + {theme.direction === "rtl" ? : } + +
+ ); } interface TablePaginationActionsProps { - count: number; - page: number; - rowsPerPage: number; - onChangePage: (event: React.MouseEvent, newPage: number) => void; + count: number; + page: number; + rowsPerPage: number; + onChangePage: ( + event: React.MouseEvent, + newPage: number + ) => void; } type Props = OwnProps; - function descendingComparator(a: any, b: any, orderBy: any) { - if (b[orderBy] < a[orderBy]) { - return -1; - } - if (b[orderBy] > a[orderBy]) { - return 1; - } - return 0; + if (b[orderBy] < a[orderBy]) { + return -1; + } + if (b[orderBy] > a[orderBy]) { + return 1; + } + return 0; } -type Order = 'asc' | 'desc'; +type Order = "asc" | "desc"; function getComparator( - order: Order, - orderBy: string, + order: Order, + orderBy: string ): (a: any, b: any) => number { - return order === 'desc' - ? (a, b) => descendingComparator(a, b, orderBy) - : (a, b) => -descendingComparator(a, b, orderBy); + return order === "desc" + ? (a, b) => descendingComparator(a, b, orderBy) + : (a, b) => -descendingComparator(a, b, orderBy); } function stableSort(array: any[], comparator: (a: any, b: any) => number) { - const stabilizedThis = array.map((el, index) => [el, index] as [any, number]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) return order; - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); + const stabilizedThis = + array && array.map((el, index) => [el, index]); + stabilizedThis.sort((a, b) => { + const order = comparator(a[0], b[0]); + if (order !== 0) return order; + return a[1] - b[1]; + }); + return stabilizedThis.map((el) => el[0]); } interface EnhancedTableProps { - classes: ReturnType; - //columns: IColumnsConfig[], - numSelected?: number; - onRequestSort: (event: React.MouseEvent, property: string) => void; - onSelectAllClick?: (event: React.ChangeEvent) => void; - order: Order; - orderBy: string; - rowCount: number; - isActive?: boolean; + classes: ReturnType; + //columns: IColumnsConfig[], + numSelected?: number; + onRequestSort: (event: React.MouseEvent, property: string) => void; + onSelectAllClick?: (event: React.ChangeEvent) => void; + order: Order; + orderBy: string; + rowCount: number; + isActive?: boolean; } - const StyledMenu = withStyles({ - paper: { - // border: '1px solid #d3d4d5', - }, + paper: { + // border: '1px solid #d3d4d5', + }, })((props: MenuProps) => ( - + )); const StyledMenuItem = withStyles((theme) => ({ - root: { - '&:focus': { - // backgroundColor: theme.palette.primary.main, - // '& .MuiListItemIcon-root, & .MuiListItemText-primary': { - // color: theme.palette.primary.main, - // }, - }, + root: { + "&:focus": { + // backgroundColor: theme.palette.primary.main, + // '& .MuiListItemIcon-root, & .MuiListItemText-primary': { + // color: theme.palette.primary.main, + // }, }, + }, }))(MenuItem); const StyledPaginationBox = withStyles((theme) => ({ + root: { + "&": { + // textAlign: '-moz-center', + textAlign: "-webkit-center", + margin: "20px auto", + // fontSize: '16px' + }, + }, +}))(Box); + +const useStyles = makeStyles((theme: Theme) => + createStyles({ root: { - '&': { - // textAlign: '-moz-center', - textAlign: '-webkit-center', - margin: '20px auto', - // fontSize: '16px' - } - } -}))(Box) - -const useStyles = makeStyles((theme: Theme) => createStyles({ - root: { - // padding: 30 - // .MuiTableCell-head - '& .MuiTableCell-root': { - fontSize: '12px', - padding: '5px', - height: '45px', - borderBottom: 'none' - }, - '& .MuiAvatar-root, & .MuiAvatar-circle, & .MuiAvatar-colorDefault': { - height: '30px', - width: '30px' - }, - '& .MuiTable-root thead th': { - fontWeight: 'bold' - } + // padding: 30 + // .MuiTableCell-head + "& .MuiTableCell-root": { + fontSize: "12px", + padding: "5px", + height: "45px", + borderBottom: "none", + }, + "& .MuiAvatar-root, & .MuiAvatar-circle, & .MuiAvatar-colorDefault": { + height: "30px", + width: "30px", + }, + "& .MuiTable-root thead th": { + fontWeight: "bold", + }, }, header: { - '& > *': { - fontWeight: 600 - } + "& > *": { + fontWeight: 600, + }, }, cell: { - borderBottom: 'none', - //padding: (config: IConfigObject) => config.cellOptions ? config.cellOptions.padding : 'auto' + borderBottom: "none", + //padding: (config: IConfigObject) => config.cellOptions ? config.cellOptions.padding : 'auto' }, pagination: { - // fontSize: '25px' + // fontSize: '25px' }, visuallyHidden: { - border: 0, - clip: 'rect(0 0 0 0)', - height: 1, - margin: -1, - overflow: 'hidden', - padding: 0, - position: 'absolute', - top: 20, - width: 1, + border: 0, + clip: "rect(0 0 0 0)", + height: 1, + margin: -1, + overflow: "hidden", + padding: 0, + position: "absolute", + top: 20, + width: 1, }, -})) - -export const TableWrapper: FunctionComponent = ({ config, ...props }) => { - const classes = useStyles(config) - - const [anchorEl, setAnchorEl] = useState(null); - const [menuId, setMenuId] = useState(null); - const [page, setPage] = React.useState(0); - const [rowsPerPage, setRowsPerPage] = React.useState(10); - const [order, setOrder] = React.useState('asc'); - const [orderBy, setOrderBy] = React.useState('id'); - const rows = [...config.data] - const columns = [...config.columns] - const menuOptions = [...config.menuOptions] - const pageChange = config.pageChange - const totalCount = config.totalCount || rows.length - const handleRequestSort = (event: React.MouseEvent, property: string) => { - const isAsc = orderBy === property && order === 'asc'; - setOrder(isAsc ? 'desc' : 'asc'); - setOrderBy(property); - }; - - const handleClick = (event: React.MouseEvent, menuId: any) => { - setAnchorEl(event.currentTarget); - setMenuId(menuId); - }; - - const handleClose = () => { - setAnchorEl(null); - setMenuId(null); - }; - - const handleChangePage = (event: React.MouseEvent | null, newPage: number) => { - setPage(newPage); - pageChange && pageChange(newPage,rowsPerPage) - }; + }) +); - const handleChangeRowsPerPage = ( - event: React.ChangeEvent, +export const TableWrapper: FunctionComponent = ({ + config, + ...props +}) => { + const classes = useStyles(config); + + const [anchorEl, setAnchorEl] = useState(null); + const [menuId, setMenuId] = useState(null); + const [page, setPage] = React.useState(0); + const [rowsPerPage, setRowsPerPage] = React.useState(10); + const [order, setOrder] = React.useState("asc"); + const [orderBy, setOrderBy] = React.useState("id"); + const rows = [...config.data]; + const columns = [...config.columns]; + const menuOptions = config.menuOptions ? [...config.menuOptions] : null; + const pageChange = config.pageChange; + const totalCount = config.totalCount || rows.length; + const handleRequestSort = ( + event: React.MouseEvent, + property: string + ) => { + const isAsc = orderBy === property && order === "asc"; + setOrder(isAsc ? "desc" : "asc"); + setOrderBy(property); + }; + + const handleClick = ( + event: React.MouseEvent, + menuId: any + ) => { + setAnchorEl(event.currentTarget); + setMenuId(menuId); + }; + + const handleClose = () => { + setAnchorEl(null); + setMenuId(null); + }; + + const handleChangePage = ( + event: React.MouseEvent | null, + newPage: number + ) => { + setPage(newPage); + pageChange && pageChange(newPage, rowsPerPage); + }; + + const handleChangeRowsPerPage = ( + event: React.ChangeEvent + ) => { + setRowsPerPage(parseInt(event.target.value, 10)); + setPage(0); + pageChange && pageChange(0, parseInt(event.target.value, 10)); + }; + + const TableHeader = ( + + {columns.map((column) => ( + {column.label} + ))} + + ); + + function EnhancedTableHead(props: EnhancedTableProps) { + const { + isActive, + classes, + onSelectAllClick, + order, + orderBy, + numSelected, + rowCount, + onRequestSort, + } = props; + const createSortHandler = (property: string) => ( + event: React.MouseEvent ) => { - setRowsPerPage(parseInt(event.target.value, 10)); - setPage(0); - pageChange && pageChange(0,parseInt(event.target.value, 10)) + onRequestSort(event, property); }; - - const TableHeader = - { - columns.map(column => ( - {column.label} - )) - } - - - function EnhancedTableHead(props: EnhancedTableProps) { - const { isActive, classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props; - const createSortHandler = (property: string) => (event: React.MouseEvent) => { - onRequestSort(event, property); - }; - - return ( - - - {columns.map((headCell: any) => ( - - {headCell.isSort && - {headCell.label} - {orderBy === headCell.id ? ( - - {order === 'desc' ? 'sorted descending' : 'sorted ascending'} - - ) : null} - } - {!headCell.isSort && headCell.label} - - ))} - - - ); - } - - - const SortableTableHeader = + + {columns.map((headCell: any) => ( + + {headCell.isSort && ( + + {headCell.label} + {orderBy === headCell.id ? ( + + {order === "desc" + ? "sorted descending" + : "sorted ascending"} + + ) : null} + + )} + {!headCell.isSort && headCell.label} + + ))} + + + ); + } + + const SortableTableHeader = ( + - const tableRows = pageChange ? (rowsPerPage > 0 - ? stableSort(rows, getComparator(order, orderBy)) - : rows - ): (rowsPerPage > 0 - ? stableSort(rows, getComparator(order, orderBy)).slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) - : rows - ) - const body = - { - tableRows.map((row: any, i: number) => ( - - { - columns.map((col: any, j: number) => {row[col.id]}) - } - - - - {menuOptions.map(({ item, key, callback }, i) => { - - return ( - { - handleClose() - callback && callback(row[key] || row.id) - }}> - { - item(row[key] || row.id) - } - - ) - })} - - - - )) - } + ); + const tableRows = pageChange + ? rowsPerPage > 0 + ? stableSort(rows, getComparator(order, orderBy)) + : rows + : rowsPerPage > 0 + ? stableSort(rows, getComparator(order, orderBy)).slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage + ) + : rows; + const body = ( + + {tableRows && + tableRows.map((row: any, i: number) => ( + + {columns.map((col: any, j: number) => ( + {row[col.id]} + ))} + {menuOptions && ( + + + + {menuOptions.map(({ item, key, callback }, i) => { + return ( + { + handleClose(); + callback && callback(row[key] || row.id); + }} + > + {item(row[key] || row.id)} + + ); + })} + + + )} + + ))} - - const skeletonBody = - { - Array(20).fill(0).map((row: any, i: number) => ( - - { - columns.map((col: any) => ) - } - - - - - )) - } + ); + + const skeletonBody = ( + + {Array(20) + .fill(0) + .map((row: any, i: number) => ( + + {columns.map((col: any) => ( + + + + ))} + + + + + ))} - - - const tableFooter = - - - + ); + + const tableFooter = ( + + + + - return ( - - - {SortableTableHeader} - {config.isLoading && skeletonBody} - {!config.isLoading && body} - -
- {config.pagination === undefined ? - {tableFooter} - : - {config.pagination && tableFooter} - } -
- ); + ); + return ( + + + {SortableTableHeader} + {config.isLoading && skeletonBody} + {!config.isLoading && body} +
+ {config.pagination === undefined ? ( + + {tableFooter} + + ) : ( + + {config.pagination && tableFooter} + + )} +
+ ); }; -export default TableWrapper; \ No newline at end of file +export default TableWrapper; diff --git a/src/features/Employees/EmployeeForm.tsx b/src/features/Employees/EmployeeForm.tsx new file mode 100644 index 0000000..1db8a41 --- /dev/null +++ b/src/features/Employees/EmployeeForm.tsx @@ -0,0 +1,174 @@ +import { Box, createStyles, Grid, makeStyles, Paper, Theme } from '@material-ui/core'; +import { ArrowBackIos } from '@material-ui/icons'; +import { RootState } from 'app/rootReducer'; +import CustomButton from 'components/Button'; +import TextInput from 'components/TextInput'; +import { setCurrentEmployee, saveEmployee, defaultInputState } from './employeeSlice'; +import * as React from 'react'; +import { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { RouteComponentProps } from 'react-router-dom'; + +const useStyles = makeStyles((theme: Theme) => createStyles({ + paper: { + backgroundColor: '#E7ECF6', + borderRadius: theme.shape.borderRadius - 5, + marginRight: 30, + height: '100%', + width: '100%' + // marginTop + }, + header: { + fontSize: '22px', + fontWeight: 'bold', + padding: theme.spacing(2, 0, 0, 4), + color: theme.palette.text.primary + }, + headerSecondary: { + fontSize: '20px', + fontWeight: 'bold', + padding: theme.spacing(0, 0, 4, 0), + color: theme.palette.text.primary, + }, + arrowBack: { + height: '30px', + verticalAlign: 'bottom', + cursor: 'pointer', + }, + rightInputs: { + marginTop: 134, + }, + button: { + marginRight: 20 + }, + inputGrid: { + marginTop: '30px', + padding: theme.spacing(1, 0, 0, 2) + } +})) + +interface OwnProps extends RouteComponentProps { +} + +type Props = OwnProps; + +const EmployeeForm: React.FC = (props) => { + const classes = useStyles() + + const dispatch = useDispatch() + + const { + currentEmployee + } = useSelector((state: RootState) => state.employees) + + const { + designation, + email, + empid, + fname, + lname, + mname, + mobile + } = currentEmployee + const inputState = currentEmployee; + + const setInputState = (employee: any) => { + dispatch(setCurrentEmployee(employee)); + } + + const id = props.match.params.employeeId + // debugger; + // useEffect(() => { + // if (employeesById[id]) { + // const tempId = employeesById[id] + // //setInputState(tempId) + // dispatch(setCurrentEmployee(tempId)); + // } + // }, [id]) + + const handleChange = (e: any) => setInputState({ + ...inputState, + [e.target.name]: e.target.value + }) + + const handleSubmit = async (e: any) => { + e.preventDefault() + + let bodyFormData = new FormData(); + bodyFormData.append('fname',fname) + bodyFormData.append('mname',mname) + bodyFormData.append('lname',lname) + bodyFormData.append('mobile',mobile) + bodyFormData.append('email',email) + bodyFormData.append('empid',empid) + bodyFormData.append('designation',designation) + + dispatch(saveEmployee(bodyFormData, () => setInputState(defaultInputState))) + } + return ( + + +
+
+ props.history.push('/employees')} /> + Add Employee +
+ + + Save + + + + + {/*
*/} + + + + + + + + + + + + + + + + ); +} + +export default EmployeeForm \ No newline at end of file diff --git a/src/features/Employees/EmployeesView.tsx b/src/features/Employees/EmployeesView.tsx index 48a8bb0..0e2fce3 100644 --- a/src/features/Employees/EmployeesView.tsx +++ b/src/features/Employees/EmployeesView.tsx @@ -1,12 +1,14 @@ -import React, {FunctionComponent, useEffect} from 'react'; +import React, { FunctionComponent, useEffect, useState } from 'react'; import TableWrapper from "../../components/TableWrapper"; -import {createStyles, fade, Grid, Paper, Theme} from "@material-ui/core"; -import {makeStyles} from "@material-ui/core/styles"; +import { Avatar, Box, createStyles, fade, Grid, Paper, Theme } from "@material-ui/core"; +import { makeStyles } from "@material-ui/core/styles"; import SearchInput from "../../components/SearchInput"; import { RootState } from 'app/rootReducer' import { useSelector, useDispatch } from 'react-redux'; import { fetchEmployees } from 'features/Employees/employeeSlice' import { CustomMenuItem } from 'components/CustomMenuItem'; +import { serverUrl } from 'api/Apis'; +import CustomButton from 'components/Button'; interface OwnProps { } @@ -24,34 +26,57 @@ const useStyles = makeStyles((theme: Theme) => ) -const data = { - name: 'Vijaya Tondon', - mobileNo: 9754821630, - email: 'Vijaytandon@gmail.com', - organization: 'Company Name' -} + //const columns = ['Visitor name', 'Mobile No.', 'Email', 'Organization'] +// designation: any,//developer, +// email: any,//arjunp@gmail.com, +// empid: any,//002, +// fname: any,//arjun, +// lname: any,//pan, +// mname: any,//test, +// mobile: any,//1any,//2345678, +// profilepicpath: const columns = [ { - id: "name", - label: 'Visitor name' + id: "profilepicpath", + label: '' + }, + { + id: "fname", + label: 'First name' + }, + { + id: "mname", + label: 'Middle name' + }, + { + id: "lname", + label: 'Last name' }, { id: "mobile", - label: 'Mobile No.' + label: 'Mobile no.' + }, + { + id: "email", + label: 'Email id' }, { - id: "tomeet", - label: 'Email' + id: "designation", + label: 'Designation' }, { - id: "purpose", - label: 'Organization' - }] + id: "empid", + label: 'Employee id' + } +] const EmployeesView: FunctionComponent = (props) => { const classes = useStyles() + const [filter, setfilter] = useState("") + const [rowPerPage, setRowPerPage] = useState(10); + const dispatch = useDispatch() const { @@ -68,6 +93,10 @@ const EmployeesView: FunctionComponent = (props) => { }, [dispatch]) + useEffect(() => { + debugger + dispatch(fetchEmployees(0, rowPerPage,filter)) + }, [filter]) if (error) { return ( @@ -78,36 +107,42 @@ const EmployeesView: FunctionComponent = (props) => { ) } - let tableRows: any = [] - - for (let i = 0; i < 10; i++) { - let copy: any = tableRows - - tableRows = [data, ...copy] - } - - const TableConfig = { columns: columns, - data: employees, + data: employees.map(el => ({ + ...el, + profilepicpath: + })), isLoading: isLoadingEmployee, - pagination:true, - pageChange:(page:number,count:number)=>{ - dispatch(fetchEmployees(page,count)) + pagination: true, + pageChange: (page: number, count: number) => { + dispatch(fetchEmployees(page, count,filter)) }, - totalCount:pageCount, - menuOptions: [{ - item: (id: any) => console.log('check out ' + id)}> - Check Out - - }] + totalCount: pageCount, + //@ts-ignore + // menuOptions: [ + // { + // item: (id: any) => console.log('check out ' + id)}> + // Check Out + // + // } + // ] } return ( - + - - + + + { setfilter(e.target.value ) }} value={filter}/*style={{ margin: '0 23px 30px', paddingTop: '37px' }}*/ placeholder="Search Employees by name" width={500} /> + {/* */} + + + Add + + + + ); diff --git a/src/features/Employees/employeeSlice.ts b/src/features/Employees/employeeSlice.ts index f218761..8103bf2 100644 --- a/src/features/Employees/employeeSlice.ts +++ b/src/features/Employees/employeeSlice.ts @@ -1,93 +1,150 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import { Links } from 'parse-link-header' - -import { getEmployeesData } from 'api/Apis' -import { AppThunk } from 'app/store' +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { Links } from "parse-link-header"; +import { createEmployee, getEmployeesData } from "api/Apis"; +import { AppThunk } from "app/store"; +import { getBackdropStart, getBackdropStop } from "app/BackdropSlice"; +import { startSnackbar } from "app/SnackbarSlice"; export interface Employee { - email: any //"admin@gmail.com", - intime: any //"2020-09-14 20:28:34", - employee_id: any //"arj1600095514", - mobileno: any //"123456789", - name: any //"arjunp", - purpose: any //"tomeet", - scheduletime: any //"2020-09-12 15:00" - tomeet: any //"arjun2" + createdOn: any; //2020-09-30 13: 14: 38, + designation: any; //developer, + email: any; //arjunp@gmail.com, + empid: any; //002, + fname: any; //arjun, + lname: any; //pan, + mname: any; //test, + mobile: any; //1any,//2345678, + profilepicpath: any; //uploads/images/arj_pic_1601471678_arjun_pass.JPG, + updatedOn: any; //2020-09-30 13: 14: 38 + name: any; } export interface EmployeesResult { - //pageLinks: Links | null - pageCount: number - employees: Employee[] + //pageLinks: Links | null + pageCount: number; + employees: Employee[]; +} + +export interface EmployeeInputState { + fname: string; + mname: string; + lname: string; + mobile: string; + email: string; + empid: string; + designation: string; } +export const defaultInputState: EmployeeInputState = { + fname: "", + mname: "", + lname: "", + mobile: "", + email: "", + empid: "", + designation: "", +}; interface EmployeeState { - employees: Employee[] - employeesById: Record - currentPageEmployees: number[] - pageCount: number - pageLinks: Links | null - isLoading: boolean - error: string | null + employees: Employee[]; + employeesById: Record; + currentPageEmployees: number[]; + pageCount: number; + pageLinks: Links | null; + isLoading: boolean; + error: string | null; + currentEmployee: EmployeeInputState; } const employeesInitialState: EmployeeState = { - employees: [], - employeesById: {}, - currentPageEmployees: [], - pageCount: 0, - pageLinks: {}, - isLoading: false, - error: null -} + employees: [], + employeesById: {}, + currentPageEmployees: [], + pageCount: 0, + pageLinks: {}, + isLoading: false, + error: null, + currentEmployee: defaultInputState, +}; function startLoading(state: EmployeeState) { - state.isLoading = true + state.isLoading = true; } function loadingFailed(state: EmployeeState, action: PayloadAction) { - state.isLoading = false - state.error = action.payload + state.isLoading = false; + state.error = action.payload; } const employees = createSlice({ - name: 'employees', - initialState: employeesInitialState, - reducers: { - - getEmployeesStart: startLoading, - getEmployeesSuccess(state, { payload }: PayloadAction) { - const { pageCount, employees } = payload - state.pageCount = pageCount - state.isLoading = false - state.error = null - state.employees = employees - // @ts-ignore - state.employees.map(employee => (state.employeesById[employee.employee_id]=employee)) - }, - getEmployeesFailure: loadingFailed, - } -}) + name: "employees", + initialState: employeesInitialState, + reducers: { + getEmployeesStart: startLoading, + getEmployeesSuccess(state, { payload }: PayloadAction) { + const { pageCount, employees } = payload; + state.pageCount = pageCount; + state.isLoading = false; + state.error = null; + state.employees = employees.map((e) => ({ + ...e, + name: e.fname + " " + e.mname + " " + e.lname, + })); + // @ts-ignore + state.employees.map( + (employee) => (state.employeesById[employee.empid] = employee) + ); + }, + getEmployeesFailure: loadingFailed, + setCurrentEmployee(state, { payload }: PayloadAction) { + state.currentEmployee = payload; + }, + }, +}); export const { - getEmployeesStart, - getEmployeesSuccess, - getEmployeesFailure -} = employees.actions + getEmployeesStart, + getEmployeesSuccess, + getEmployeesFailure, + setCurrentEmployee, +} = employees.actions; -export default employees.reducer +export default employees.reducer; export const fetchEmployees = ( - page?: number - , count?: number -): AppThunk => async dispatch => { - try { - dispatch(getEmployeesStart()) - const employees = await getEmployeesData(page,count) + page?: number, + count?: number, + filter?: string +): AppThunk => async (dispatch) => { + try { + dispatch(getEmployeesStart()); + const employees = await getEmployeesData(page, count, filter); - dispatch(getEmployeesSuccess(employees)) - } catch (err) { - dispatch(getEmployeesFailure(err.toString())) - } -} + dispatch(getEmployeesSuccess(employees)); + } catch (err) { + dispatch(getEmployeesFailure(err.toString())); + } +}; +export const saveEmployee = ( + employeeFormData: any, + callback?: () => void +): AppThunk => async (dispatch) => { + try { + dispatch(getBackdropStart()); + await createEmployee(employeeFormData) + .then(() => { + dispatch(getBackdropStop()); + dispatch(startSnackbar({ message: "Employee created" })); + }) + .catch(() => { + dispatch(getBackdropStop()); + dispatch(startSnackbar({ message: "Something went wrong" })); + }); + //return setInputState(defaultInputState) + callback && callback(); + //dispatch(saveInvitesSuccess(invites)) + } catch (err) { + dispatch(getBackdropStop()); + dispatch(startSnackbar({ message: "Something went wrong" })); + } +}; diff --git a/src/features/Home/HomeDateDropdown.tsx b/src/features/Home/HomeDateDropdown.tsx index 748005e..9d1d491 100644 --- a/src/features/Home/HomeDateDropdown.tsx +++ b/src/features/Home/HomeDateDropdown.tsx @@ -23,7 +23,7 @@ const useStyles = makeStyles((theme: Theme) => '& .MuiInput-underline:before, & .MuiInput-underline:after': { borderBottom: 'none !important' }, - '& #date-picker-inline': { + '& #date-picker-inline2': { fontWeight: 600, color: theme.palette.text.primary, fontSize: '20px', @@ -85,7 +85,7 @@ const HomeDateDropdown: FunctionComponent = (props) => { variant="inline" format="MMM dd, yyyy" margin="normal" - id="date-picker-inline" + id="date-picker-inline2" autoOk value={selectedDate} onChange={handleDateChange} diff --git a/src/features/Home/HomeView.tsx b/src/features/Home/HomeView.tsx index 02654ca..10ce0db 100644 --- a/src/features/Home/HomeView.tsx +++ b/src/features/Home/HomeView.tsx @@ -26,14 +26,15 @@ import TableWrapper from "components/TableWrapper"; import SearchInput from "components/SearchInput"; import SelectInput from "components/SelectInput"; import { useSelector, useDispatch } from 'react-redux'; -import { fetchVisitors } from 'features/Home/visitorSlice' +import { fetchInOfficeVisitors, fetchVisitors, setFilter } from 'features/Home/visitorSlice' import { fetchHomeStats } from 'features/Home/homeSlice' import { RootState } from 'app/rootReducer' import { MyChart2 } from 'components/Chart' import { CustomMenuItem } from 'components/CustomMenuItem'; import Axios from 'axios'; -import { apis, checkout } from 'api/Apis'; +import { apis, checkout, serverUrl } from 'api/Apis'; import { getBackdropStart, getBackdropStop } from 'app/BackdropSlice'; +import CustomizedSwitch from 'components/Switch'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -98,6 +99,14 @@ const useStyles = makeStyles((theme: Theme) => transition: theme.transitions.create('width'), }, + label: { + textTransform: 'capitalize' + }, + buttonRoot: { + backgroundColor: 'white', + boxShadow: 'none', + borderRadius: theme.shape.borderRadius - 5 + } }) ) @@ -109,12 +118,34 @@ type Props = OwnProps; const HomeView: FunctionComponent = (props) => { const classes = useStyles() + const [rowPerPage, setRowPerPage] = useState(10); const [anchorEl, setAnchorEl] = useState(null); - + const [filter, setFilter] = useState({ visitor: "", purpose: "", site: "" }) const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; + const [inOffice, setInOffice] = useState(false); + const setInOffice1 = (flag:boolean)=>{ + setInOffice(flag) + //flag ? dispatch(fetchInOfficeVisitors()) : dispatch(fetchVisitors()); + } + + const doFetch=(page=0, count=10, visitor="", purpose="", site="")=>{ + inOffice? dispatch(fetchInOfficeVisitors(page, count, visitor, purpose, site)): dispatch(fetchVisitors(page, count, visitor, purpose, site)) + } + const handleFilterChange = (f: any) => { + debugger; + const newFilter = { ...filter, ...f } + setFilter(newFilter) + const { + purpose: purpose1, + site: site1, + visitor: visitor1 + } = newFilter + //dispatch(fetchVisitors(0, rowPerPage, visitor1, purpose1, site1)) + //doFetch(0, rowPerPage, visitor1, purpose1, site1) + } const handleClose = () => { setAnchorEl(null); }; @@ -151,17 +182,21 @@ const HomeView: FunctionComponent = (props) => { isSort: true }] - let tableRows: any = [] + const dispatch = useDispatch() + const { + sites + } = useSelector((state: RootState) => state.sites) const { visitors, currentPageVisitors, pageCount, pageLinks, isLoading: isLoadingVisitor, - error + error, + purpose } = useSelector((state: RootState) => state.visitors) const { @@ -175,16 +210,28 @@ const HomeView: FunctionComponent = (props) => { } = useSelector((state: RootState) => state.home) useEffect(() => { - dispatch(fetchVisitors(0,10)) + //dispatch(fetchVisitors(0, 10)) + doFetch(0, 10) dispatch(fetchHomeStats()) }, [dispatch]) + useEffect(() => { + + const { + purpose: purpose1, + site: site1, + visitor: visitor1 + } = filter + doFetch(0, rowPerPage, visitor1, purpose1, site1) + }, [inOffice,filter]) + const handleCheckOut = async (id: any) => { dispatch(getBackdropStart()) await checkout(id) .then(() => { dispatch(fetchHomeStats()) - dispatch(fetchVisitors(0,10)) + //dispatch(fetchVisitors(0, 10)) + doFetch(0, 10) dispatch(getBackdropStop()) }) .catch(() => dispatch(getBackdropStop())) @@ -202,25 +249,29 @@ const HomeView: FunctionComponent = (props) => { const TableConfig = { columns: columns, - isLoading: isLoadingHomeStats, + isLoading: isLoadingVisitor, data: visitors.map(el => ({ ...el, - profilePicPath: + profilePicPath: })), - pagination:true, - pageChange:(page:number,count:number)=>{ - dispatch(fetchVisitors(page,count)) + pagination: true, + pageChange: (page: number, count: number) => { + const { + purpose: purpose1, + site: site1, + visitor: visitor1 + } = filter + setRowPerPage(count) + //dispatch(fetchVisitors(page, count, visitor1, purpose1, site1)) + doFetch(page, count, visitor1, purpose1, site1) }, - totalCount:pageCount, + totalCount: pageCount, menuOptions: [{ key: 'checkin_id', callback: handleCheckOut, item: (id: any) => { - return ( { - - } - }> + return ( {'Check Out'} ) } @@ -264,15 +315,34 @@ const HomeView: FunctionComponent = (props) => { - + {/* Old gap 30px */} + - - - - + { debugger; handleFilterChange({ visitor: e.target.value }) }} value={filter.visitor} placeholder="Search visitor" /> + {/* */} + { setInOffice(!inOffice) }} /> + {/* */} + { debugger; handleFilterChange({ purpose: e.target.value }) }} menuOptions={purpose.map(item => ({ title: item }))} defaultValue="All Purpose" value={filter.purpose} /> + { debugger; handleFilterChange({ site: e.target.value }) }} menuOptions={sites.map(item => ({ title: item.sitename }))} defaultValue="All Sites" value={filter.site} /> + + - + diff --git a/src/features/Home/VisitorDetailsView1.tsx b/src/features/Home/VisitorDetailsView1.tsx new file mode 100644 index 0000000..5069b16 --- /dev/null +++ b/src/features/Home/VisitorDetailsView1.tsx @@ -0,0 +1,521 @@ +import { Box, createStyles, Grid, Paper } from "@material-ui/core"; +import { makeStyles } from "@material-ui/core/styles"; +import { Theme } from "@material-ui/core/styles/createMuiTheme"; +import { ArrowBackIos, CameraAlt } from "@material-ui/icons"; +import { getBackdropStart, getBackdropStop } from "app/BackdropSlice"; +import { + setCurrentVisitor, + defaultVisitor, + fetchVisitors, +} from "features/Home/visitorSlice"; +import React, { FunctionComponent, useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { RouteComponentProps } from "react-router-dom"; +import { apis, serverUrl } from "../../api/Apis"; +import { RootState } from "../../app/rootReducer"; +import CustomButton from "../../components/Button"; +import SelectInput from "../../components/SelectInput"; +import TextInput from "../../components/TextInput"; +import { config as VisitorFormConfig } from "features/Settings/VisitorFormConfig"; +import { fetchVisitorConfigs } from "features/Settings/visitorConfigSlice"; +import img from "assets/logo/logo.png"; +import { fetchSites } from "features/SalesAndOrganisation/siteSlice"; +import { fetchEmployees } from "features/Employees/employeeSlice"; +import { startSnackbar } from "app/SnackbarSlice"; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + paper: { + backgroundColor: "#E7ECF6", + borderRadius: theme.shape.borderRadius - 5, + marginRight: 20, + height: "100%", + }, + header: { + fontSize: "20px", + fontWeight: "bold", + padding: theme.spacing(2, 0, 0, 4), + color: theme.palette.text.primary, + }, + headerSecondary: { + fontSize: "18.75px", + fontWeight: "bold", + padding: theme.spacing(0, 0, 2, 0), + color: theme.palette.text.primary, + }, + arrowBack: { + height: "16px", + // verticalAlign: 'bottom', + cursor: "pointer", + }, + imageContainer: { + padding: theme.spacing(3, 0, 0, 8), + }, + imageUpload: { + position: "relative", + backgroundColor: "#fff", + height: 86, + width: 86, + textAlign: "center", + borderRadius: theme.shape.borderRadius, + "& > svg": { + height: "100%", + opacity: 0.7, + fontSize: "44px", + }, + }, + visitorInfo: { + padding: theme.spacing(2, 0, 1, 8), + }, + appointment: { + padding: theme.spacing(1, 0, 2, 8), + }, + rightInputs: { + marginTop: 117, + }, + button: { + // marginRight: 20 + }, + selectInput: { + "& > .makeStyles-inputContainer-32": { + // padding: 0 + }, + }, + }) +); + +const selectInputMenu = [ + { + title: "Check Out", + }, + { + title: "Alert", + }, +]; + +interface OwnProps extends RouteComponentProps { } + +type Props = OwnProps; + +const VisitorDetailsView: FunctionComponent = (props) => { + const classes = useStyles(); + + const dispatch = useDispatch(); + const { visitorConfigsById, isLoading, error: configError } = useSelector( + (state: RootState) => state.visitorConfig + ); + const defaultInputState = { + id: 0, + avatar: "", + name: "", + mobileNo: "", + personToMeet: "", + purpose: "", + inTime: "", + outTime: "", + type: "", + noOfVisitors: "", + city: "", + email: "", + visitorCompany: "", + country: "", + site: "", + host: "", + gender: "", + }; + + //const [inputState, setInputState] = useState(defaultInputState) + const handleChange = (e: any) => { + dispatch( + setCurrentVisitor({ + ...currentVisitor, + [e.target.name]: e.target.value, + }) + ); + }; + + const { + visitors, + visitorsById, + currentVisitor, + purpose: purposeOptions, + isLoading: isLoadingVisitor, + error, + } = useSelector((state: RootState) => state.visitors); + const { sites } = useSelector((state: RootState) => state.sites); + const { employees } = useSelector((state: RootState) => state.employees); + //const inputState = currentVisitor + const { mask } = useSelector((state: RootState) => state.backdrop); + + const { + answer1, + answer3, + answer4, + answer5, + belongings, + checkin_id, + city, + company, + country, + email, + gender, + idCardImagePath, + idtype, + intime, + mobile, + name, + ndastatus, + noofvisitor, + organisation, + outime, + policycheckstatus, + profilePicPath, + purpose, + signaturePath, + site, + tomeet, + usertype, + answer2, + vehicleno, + } = currentVisitor; + const id = props.match.params.visitorId; + useEffect(() => { + id != -1 && dispatch(setCurrentVisitor(visitorsById[id] || defaultVisitor)); + }, [id]); + + useEffect(() => { + dispatch(fetchVisitors()); + dispatch(fetchSites()); + dispatch(fetchEmployees()); + }, [dispatch]); + + const handleSubmit = async (e: any) => { + dispatch(getBackdropStart()); + let bodyFormData = new FormData(); + bodyFormData.append("profilepic", "arjun_pass.jpg"); + bodyFormData.append("idcard", "arjun_pass.jpg"); + bodyFormData.append("signature", "arjun_pass.jpg"); + bodyFormData.append("name", name); + bodyFormData.append("mobile", mobile); + bodyFormData.append("tomeet", tomeet); + bodyFormData.append("email", email); + bodyFormData.append("purpose", purpose); + bodyFormData.append("gender", gender); + bodyFormData.append("visitorcount", noofvisitor); + bodyFormData.append("company", company); + bodyFormData.append("country", country); + bodyFormData.append("organisation", organisation); + bodyFormData.append("site", site); + bodyFormData.append("vehicleno", vehicleno); + bodyFormData.append("belongings", belongings); + bodyFormData.append("idtype", idtype); + bodyFormData.append("city", city); + bodyFormData.append("answer1", answer1); + bodyFormData.append("answer2", answer2); + bodyFormData.append("answer3", answer3); + bodyFormData.append("answer4", answer4); + bodyFormData.append("answer5", answer5); + bodyFormData.append("ndacheck", ndastatus); + bodyFormData.append("policycheck", policycheckstatus); + bodyFormData.append("usertype", usertype); + await apis + .post("/product/reception/user/checkin", bodyFormData, { + headers: { + Accept: "*/*", + "Cache-Control": "no-cache", + "Accept-Encoding": "gzip, deflate, br", + Connection: "keep-alive", + "Content-Type": "multipart/form-data", + "Content-Length": 2617, + }, + }) + .then(() => { + dispatch(getBackdropStop()); + dispatch(startSnackbar({ message: "Visitor checked in" })); + }) + .catch(() => { + dispatch(getBackdropStop()); + dispatch(startSnackbar({ message: "Something went wrong" })); + }); + }; + + const handlePurpose = (value: any) => { + dispatch( + setCurrentVisitor({ + ...currentVisitor, + purpose: value, + }) + ); + }; + + const handleAutoComplete = (obj: any) => { + dispatch( + setCurrentVisitor({ + ...currentVisitor, + ...obj, + }) + ); + }; + + const visitorSectionFields = VisitorFormConfig.filter( + (i) => + i.section === "VI" && + visitorConfigsById[i.id] && + visitorConfigsById[i.id].value + ) + .sort((a, b) => a.seq - b.seq) + .map((o, i) => ( + + {/* {(o.render && o.render(notificationById[i], handleChange, i + "-" + o.key)) || obj[o.key]} */} + {/* */} + {o.component ? ( + o.component({ + purpose: { + options: purposeOptions, + onChange: handleAutoComplete, + value: purpose, + }, + visitors: { + options: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], + onChange: handleAutoComplete, + value: noofvisitor, + }, + style: { + width: 446, + marginLeft: i % 2 === 0 ? "64px" : "28px", + }, + }) + ) : ( + + )} + + )); + const appointmentSectionFields = VisitorFormConfig.filter( + (i) => + i.section === "AR" && + visitorConfigsById[i.id] && + visitorConfigsById[i.id].value + ) + .sort((a, b) => a.seq - b.seq) + .map((o, i) => ( + + {/* {(o.render && o.render(notificationById[i], handleChange, i + "-" + o.key)) || obj[o.key]} */} + {o.component ? ( + o.component({ + site: { + options: sites.map((o) => o.sitename), //siteOptions || + onChange: handleAutoComplete, + value: site, + }, + person: { + options: employees.map((o) => o.fname + " " + o.lname), //siteOptions || + onChange: handleAutoComplete, + value: tomeet, + }, + style: { + width: 446, + marginLeft: i % 2 === 0 ? "64px" : "28px", + }, + }) + ) : ( + + )} + + )); + + useEffect(() => { + //dispatch(fetchVisitorConfigs()) + }, [dispatch]); + return ( + + +
+
+ props.history.push("/")} + /> + Visitor's Details +
+ + + + +
+ {profilePicPath ? ( + + ) : ( + + )} +
+
+ +
+ {idCardImagePath ? ( + + ) : ( + + )} +
+
+ +
+ {signaturePath ? ( + + ) : ( + + )} +
+
+
+
+ + + + + + Save + + + + +
+ + +
+ + Visitor's information + + + + + + + + + +
+
+ + {visitorSectionFields} + {/* + + + + + + */} +
+ + +
+ + Appointments requests + + {/* + */} +
+
+ {/* + + */} + + {appointmentSectionFields} +
+
+
+
+ ); +}; + +export default VisitorDetailsView; diff --git a/src/features/Home/homeSlice.ts b/src/features/Home/homeSlice.ts index cb10206..ad06d9b 100644 --- a/src/features/Home/homeSlice.ts +++ b/src/features/Home/homeSlice.ts @@ -1,16 +1,15 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { getHomeStats } from 'api/Apis'; -import { AppThunk } from 'app/store'; - +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { getHomeStats } from "api/Apis"; +import { AppThunk } from "app/store"; interface homeStatsState { - checked_out: number - in_office: number - invite_sent: number - total_visitor: number - visitors: number[] - isLoading: boolean - error: string | null + checked_out: number; + in_office: number; + invite_sent: number; + total_visitor: number; + visitors: number[]; + isLoading: boolean; + error: string | null; } const homeStatsInitialState: homeStatsState = { @@ -20,61 +19,58 @@ const homeStatsInitialState: homeStatsState = { total_visitor: 0, visitors: [], isLoading: false, - error: null -} + error: null, +}; function startLoading(state: homeStatsState) { - state.isLoading = true + state.isLoading = true; } function loadingFailed(state: homeStatsState, action: PayloadAction) { - state.isLoading = false - state.error = action.payload + state.isLoading = false; + state.error = action.payload; } - const homeStats = createSlice({ - name: 'homeStats', + name: "homeStats", initialState: homeStatsInitialState, reducers: { - getHomeStatsStart: startLoading, getHomeStatsSuccess(state, { payload }: PayloadAction) { - const { checked_out, + const { + checked_out, in_office, invite_sent, total_visitor, visitors, - isLoading } = payload - state.checked_out = checked_out - state.in_office = in_office - state.invite_sent = invite_sent - state.total_visitor = total_visitor - state.isLoading = false - state.error = null - state.visitors = visitors + isLoading, + } = payload; + state.checked_out = checked_out; + state.in_office = in_office; + state.invite_sent = invite_sent; + state.total_visitor = total_visitor; + state.isLoading = false; + state.error = null; + state.visitors = visitors; }, getHomeStatsFailure: loadingFailed, - } -}) + }, +}); export const { getHomeStatsStart, getHomeStatsSuccess, getHomeStatsFailure, -} = homeStats.actions +} = homeStats.actions; -export default homeStats.reducer +export default homeStats.reducer; -export const fetchHomeStats = ( - page?: number -): AppThunk => async dispatch => { +export const fetchHomeStats = (page?: number): AppThunk => async (dispatch) => { try { - dispatch(getHomeStatsStart()) - const stats = await getHomeStats() - dispatch(getHomeStatsSuccess(stats.data)) + dispatch(getHomeStatsStart()); + const stats = await getHomeStats(); + dispatch(getHomeStatsSuccess(stats.data)); } catch (err) { - dispatch(getHomeStatsFailure(err.toString())) + dispatch(getHomeStatsFailure(err.toString())); } -} - +}; diff --git a/src/features/Home/visitorSlice.ts b/src/features/Home/visitorSlice.ts index 42dffed..580cfe4 100644 --- a/src/features/Home/visitorSlice.ts +++ b/src/features/Home/visitorSlice.ts @@ -1,8 +1,9 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { Links } from 'parse-link-header' -import { VisitorsResult, getVisitorInfo, getVisitorData } from 'api/Apis' +import { VisitorsResult, getVisitorData, getPurpose, getInOfficeVisitorData } from 'api/Apis' import { AppThunk } from 'app/store' +import { fetchSites } from 'features/SalesAndOrganisation/siteSlice' export interface VisitorInfo { answer1: any, @@ -69,14 +70,16 @@ export const defaultVisitor: VisitorInfo = { } interface VisitorState { - visitors: VisitorInfo[] + visitors: VisitorInfo[], visitorsById: any, - currentVisitor: VisitorInfo - currentPageVisitors: number[] - pageCount: number - pageLinks: Links | null - isLoading: boolean - error: string | null + currentVisitor: VisitorInfo, + currentPageVisitors: number[], + pageCount: number, + pageLinks: Links | null, + isLoading: boolean, + error: string | null, + purpose: any[], + filter: any, } const visitorsInitialState: VisitorState = { @@ -87,7 +90,9 @@ const visitorsInitialState: VisitorState = { pageCount: 0, pageLinks: {}, isLoading: false, - error: null + error: null, + purpose: [], + filter: { visitor: "", purpose: "All Purpose", site: "All Sites" } } function startLoading(state: VisitorState) { @@ -115,9 +120,16 @@ const visitors = createSlice({ state.visitors.map(visitor => (state.visitorsById[visitor.checkin_id] = visitor)) //state.visitorsById = state.visitors.map(visitor => ({ ...visitor, id: visitor.id })) }, + getPurposeSuccess(state, { payload }: PayloadAction) { + const { purpose } = payload + state.purpose = purpose + }, getVisitorsFailure: loadingFailed, setCurrentVisitor(state, { payload }: PayloadAction) { state.currentVisitor = payload + }, + setFilter(state, { payload }: PayloadAction) { + state.filter = { ...state.filter, ...payload } } } }) @@ -126,23 +138,50 @@ export const { getVisitorsStart, getVisitorsSuccess, getVisitorsFailure, - setCurrentVisitor + setCurrentVisitor, + getPurposeSuccess, + setFilter } = visitors.actions export default visitors.reducer export const fetchVisitors = ( - page?: number - , count?: number + page?: number, + count?: number, + visitor?: string, + purpose?: string, + site?: string ): AppThunk => async dispatch => { try { + dispatch(fetchSites()) dispatch(getVisitorsStart()) - const visitors = await getVisitorData(page,count) - + const visitors = await getVisitorData(page, count, visitor, purpose, site) dispatch(getVisitorsSuccess(visitors)) + + const pur = await getPurpose() + dispatch(getPurposeSuccess(pur)) } catch (err) { dispatch(getVisitorsFailure(err.toString())) } } +export const fetchInOfficeVisitors = ( + page?: number, + count?: number, + visitor?: string, + purpose?: string, + site?: string +): AppThunk => async dispatch => { + try { + dispatch(fetchSites()) + dispatch(getVisitorsStart()) + const visitors = await getInOfficeVisitorData(page, count, visitor, purpose, site) + dispatch(getVisitorsSuccess(visitors)) + + const pur = await getPurpose() + dispatch(getPurposeSuccess(pur)) + } catch (err) { + dispatch(getVisitorsFailure(err.toString())) + } +} diff --git a/src/features/Invites/InviteForm.tsx b/src/features/Invites/InviteForm.tsx index ff5fe8e..05d7764 100644 --- a/src/features/Invites/InviteForm.tsx +++ b/src/features/Invites/InviteForm.tsx @@ -5,14 +5,18 @@ import { Theme } from "@material-ui/core/styles/createMuiTheme"; import { ArrowBackIos } from "@material-ui/icons"; import { DateTimePicker, MuiPickersUtilsProvider } from '@material-ui/pickers'; import { getBackdropStart, getBackdropStop } from 'app/BackdropSlice'; -import React, { FunctionComponent, useState } from 'react'; -import { useDispatch } from "react-redux"; +import React, { FunctionComponent, useEffect, useState } from 'react'; +import { useDispatch, useSelector } from "react-redux"; import { RouteComponentProps } from 'react-router-dom'; import { createInvite } from "../../api/Apis"; import CustomButton from "../../components/Button"; import TextInput from "../../components/TextInput"; import DateTimeInput from 'components/DateTimeInput' import { saveInvite } from 'features/Invites/inviteSlice' +import { RootState } from 'app/rootReducer'; +import { CustomAutoComplete } from 'components/CustomAutoComplete'; +import { fetchVisitors } from 'features/Home/visitorSlice'; +import { fetchEmployees } from 'features/Employees/employeeSlice'; const useStyles = makeStyles((theme: Theme) => createStyles({ paper: { backgroundColor: '#E7ECF6', @@ -95,18 +99,22 @@ const InviteForm: FunctionComponent = (props) => { name: '', mobileNo: '', personToMeet: '', - purpose: '', + purpose: 'default', email: '', }) - const handleChange = (e: any) => setInputState({ + const handleChange = (e: any) => {debugger;setInputState({ ...inputState, [e.target.name]: e.target.value - }) + })} const handleDateChange = (date: Date | null) => setInputState({ ...inputState, 'time': date }) + const handlePurpose = (value: any) => setInputState({ + ...inputState, + purpose: value + }) const handleSubmit = async (e: any) => { e.preventDefault() @@ -128,6 +136,11 @@ const InviteForm: FunctionComponent = (props) => { }), () => setInputState(defaultInputState))) } + const { + employees + } = useSelector((state: RootState) => state.employees) + const {purpose} = useSelector((state: RootState) => state.visitors) + // const { // visitors, // visitorsById, @@ -137,12 +150,11 @@ const InviteForm: FunctionComponent = (props) => { // // // const id = props.match.params.visitorId - // useEffect(() => { - // if (visitorsById[id]) { - // setInputState(visitorsById[id]) - // } - // console.log(visitors, inputState) - // }, [id]) + useEffect(() => { + dispatch(fetchVisitors()) + dispatch(fetchEmployees(0,9999999)) + }, [dispatch]) + return ( @@ -193,17 +205,28 @@ const InviteForm: FunctionComponent = (props) => { onChange={handleChange} name="email" value={inputState.email} /> - - */} + o.fname + " " + o.lname)} + label="Person To Meet" + onChange={(val:any)=>setInputState({ + ...inputState, + personToMeet:val + })} + name="personToMeet" + value={inputState.personToMeet} /> + diff --git a/src/features/Invites/InviteView.tsx b/src/features/Invites/InviteView.tsx index 8f3e45d..f27c2c1 100644 --- a/src/features/Invites/InviteView.tsx +++ b/src/features/Invites/InviteView.tsx @@ -25,7 +25,7 @@ import TableWrapper from "../../components/TableWrapper"; import SearchInput from "../../components/SearchInput"; import SelectInput from "../../components/SelectInput"; import { useSelector, useDispatch } from 'react-redux'; -import { fetchInvites } from 'features/Invites/inviteSlice' +import { fetchInOfficeInvites, fetchInvites } from 'features/Invites/inviteSlice' import { RootState } from 'app/rootReducer' import { CustomMenuItem } from 'components/CustomMenuItem'; import HomeDateDropdown from 'features/Home/HomeDateDropdown'; @@ -97,6 +97,14 @@ const useStyles = makeStyles((theme: Theme) => }, }, }, + label: { + textTransform: 'capitalize' + }, + buttonRoot: { + backgroundColor: 'white', + boxShadow: 'none', + borderRadius: theme.shape.borderRadius - 5 + } }) ) @@ -137,6 +145,8 @@ const InviteView: FunctionComponent = (props) => { const classes = useStyles() const [anchorEl, setAnchorEl] = useState(null); + const [filter, setFilter] = useState({ visitor: "", purpose: "", site: "" }) + const [rowPerPage, setRowPerPage] = useState(10); const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); @@ -146,12 +156,14 @@ const InviteView: FunctionComponent = (props) => { setAnchorEl(null); }; - let tableRows: any = [] - - - const dispatch = useDispatch() + const { + sites + } = useSelector((state: RootState) => state.sites) + const { + purpose + } = useSelector((state: RootState) => state.visitors) const { invites, currentPageInvites, @@ -176,13 +188,13 @@ const InviteView: FunctionComponent = (props) => { ) } - const toVisitor = (id:any)=>{ - const visitor = {...mapVisitorFromInvite(id)} + const toVisitor = (id: any) => { + const visitor = { ...mapVisitorFromInvite(id) } dispatch(setCurrentVisitor(visitor)) } - const mapVisitorFromInvite: (id:any)=>VisitorInfo = (id:any)=>{ - - let visitor: VisitorInfo = {...defaultVisitor} + const mapVisitorFromInvite: (id: any) => VisitorInfo = (id: any) => { + + let visitor: VisitorInfo = { ...defaultVisitor } const invite = invitesById[id] visitor.email = invite.email //visitor.intime = invite.intime @@ -190,7 +202,20 @@ const InviteView: FunctionComponent = (props) => { visitor.name = invite.name visitor.purpose = invite.purpose visitor.tomeet = invite.tomeet - return {...visitor} + return { ...visitor } + } + + const handleFilterChange = (f: any) => { + debugger; + const newFilter = { ...filter, ...f } + setFilter(newFilter) + const { + purpose: purpose1, + site: site1, + visitor: visitor1 + } = newFilter + + dispatch(fetchInvites(0, rowPerPage, visitor1, purpose1, site1)) } const TableConfig = { @@ -201,10 +226,16 @@ const InviteView: FunctionComponent = (props) => { })), isLoading: isLoadingInvites, pagination: true, - pageChange:(page:number,count:number)=>{ - dispatch(fetchInvites(page,count)) + pageChange: (page: number, count: number) => { + const { + purpose: purpose1, + site: site1, + visitor: visitor1 + } = filter + setRowPerPage(count) + dispatch(fetchInvites(page, count, visitor1, purpose1, site1)) }, - totalCount:pageCount, + totalCount: pageCount, menuOptions: [{ key: 'invite_id', callback: toVisitor, @@ -217,14 +248,29 @@ const InviteView: FunctionComponent = (props) => { return ( - - + + - + {/* - + */} + { debugger; handleFilterChange({ visitor: e.target.value }) }} value={filter.visitor} placeholder="Search visitor" /> + {/* */} + {/* */} + { debugger; handleFilterChange({ purpose: e.target.value }) }} menuOptions={purpose.map(item => ({ title: item }))} defaultValue="All Purpose" value={filter.purpose} /> + {/* { debugger; handleFilterChange({ site: e.target.value }) }} menuOptions={sites.map(item => ({ title: item.sitename }))} defaultValue="All Sites" value={filter.site} /> */} + diff --git a/src/features/Invites/inviteSlice.ts b/src/features/Invites/inviteSlice.ts index f599ee8..21bc38d 100644 --- a/src/features/Invites/inviteSlice.ts +++ b/src/features/Invites/inviteSlice.ts @@ -1,35 +1,38 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { Links } from 'parse-link-header' -import { getInvitesData, createInvite } from 'api/Apis' +import { getInvitesData, createInvite, getPurpose, getInOfficeInviteData } from 'api/Apis' import { AppThunk } from 'app/store' -import {getBackdropStart, getBackdropStop} from 'app/BackdropSlice' +import { getBackdropStart, getBackdropStop } from 'app/BackdropSlice' +import { fetchSites } from 'features/SalesAndOrganisation/siteSlice' +import { getPurposeSuccess } from 'features/Home/visitorSlice' +import { startSnackbar } from 'app/SnackbarSlice' export interface Invite { - email: any //"admin@gmail.com", - intime: any //"2020-09-14 20:28:34", - invite_id: any //"arj1600095514", - mobileno: any //"123456789", - name: any //"arjunp", - purpose: any //"tomeet", - scheduletime: any //"2020-09-12 15:00" + email: any, //"admin@gmail.com", + intime: any, //"2020-09-14 20:28:34", + invite_id: any,//"arj1600095514", + mobileno: any, //"123456789", + name: any, //"arjunp", + purpose: any, //"tomeet", + scheduletime: any, //"2020-09-12 15:00" tomeet: any //"arjun2" } export interface InvitesResult { //pageLinks: Links | null - pageCount: number - invites: Invite[] + pageCount: number, + invites: Invite[], } interface InviteState { - invites: Invite[] - invitesById: Record - currentPageInvites: number[] - pageCount: number - pageLinks: Links | null - isLoading: boolean - error: string | null + invites: Invite[], + invitesById: Record, + currentPageInvites: number[], + pageCount: number, + pageLinks: Links | null, + isLoading: boolean, + error: string | null, } const invitesInitialState: InviteState = { @@ -58,13 +61,13 @@ const invites = createSlice({ getInvitesStart: startLoading, getInvitesSuccess(state, { payload }: PayloadAction) { - const { pageCount, invites } = payload + const { pageCount, invites } = payload state.pageCount = pageCount state.isLoading = false state.error = null state.invites = invites // @ts-ignore - state.invites.map(invite => (state.invitesById[invite.invite_id]=invite)) + state.invites.map(invite => (state.invitesById[invite.invite_id] = invite)) }, getInvitesFailure: loadingFailed, } @@ -80,13 +83,19 @@ export default invites.reducer export const fetchInvites = ( page?: number, - count?: number + count?: number, + visitor?: string, + purpose?: string, + site?: string ): AppThunk => async dispatch => { try { + dispatch(fetchSites()) dispatch(getInvitesStart()) - const invites = await getInvitesData(page,count) + const invites = await getInvitesData(page, count, visitor, purpose, site) dispatch(getInvitesSuccess(invites)) + const pur = await getPurpose() + dispatch(getPurposeSuccess(pur)) } catch (err) { dispatch(getInvitesFailure(err.toString())) } @@ -94,18 +103,44 @@ export const fetchInvites = ( export const saveInvite = ( invite: any, - callback?:Function + callback?: Function ): AppThunk => async dispatch => { try { //dispatch(saveInviteStart()) dispatch(getBackdropStart()) await createInvite(invite) - .then(() => dispatch(getBackdropStop())).catch(() => dispatch(getBackdropStop())) + .then(() => { + dispatch(getBackdropStop()) + dispatch(startSnackbar({ message: 'Your invitee has been invited' })) + }) + .catch(() => { + dispatch(getBackdropStop()) + dispatch(startSnackbar({ message: 'Something went wrong' })) + }) //return setInputState(defaultInputState) callback && callback(); //dispatch(saveInvitesSuccess(invites)) } catch (err) { //dispatch(saveInvitesFailure(err.toString())) dispatch(getBackdropStop()) + dispatch(startSnackbar({ message: 'Something went wrong' })) + } +} + + +export const fetchInOfficeInvites = ( + page?: number + , count?: number +): AppThunk => async dispatch => { + try { + dispatch(fetchSites()) + dispatch(getInvitesStart()) + const visitors = await getInOfficeInviteData() + dispatch(getInvitesSuccess(visitors)) + + const purpose = await getPurpose() + dispatch(getPurposeSuccess(purpose)) + } catch (err) { + dispatch(getInvitesFailure(err.toString())) } } diff --git a/src/features/SalesAndOrganisation/CheckInPointForm.tsx b/src/features/SalesAndOrganisation/CheckInPointForm.tsx new file mode 100644 index 0000000..204a692 --- /dev/null +++ b/src/features/SalesAndOrganisation/CheckInPointForm.tsx @@ -0,0 +1,165 @@ +import { Box, createStyles, Grid, Paper } from "@material-ui/core"; +import { makeStyles } from "@material-ui/core/styles"; +import { Theme } from "@material-ui/core/styles/createMuiTheme"; +import { ArrowBackIos } from "@material-ui/icons"; +// import { saveCheckInPoint, setCurrentCheckInPoint } from './checkInPointSlice'; +import { RootState } from 'app/rootReducer'; +import CustomButton from "components/Button"; +import { CustomAutoComplete } from "components/CustomAutoComplete"; +import TextInput from "components/TextInput"; +import React, { FunctionComponent, useEffect } from 'react'; +import { useDispatch, useSelector } from "react-redux"; +import { RouteComponentProps } from 'react-router-dom'; +import { CheckInPointInputState, defaultInputState, saveCheckInPoint, setCurrentCheckInPoint } from './checkInPointSlice'; +import { fetchSites } from "./siteSlice"; + +const useStyles = makeStyles((theme: Theme) => createStyles({ + paper: { + backgroundColor: '#E7ECF6', + borderRadius: theme.shape.borderRadius - 5, + marginRight: 30, + height: '100%', + width: '100%' + // marginTop + }, + header: { + fontSize: '22px', + fontWeight: 'bold', + padding: theme.spacing(2, 0, 0, 4), + color: theme.palette.text.primary + }, + headerSecondary: { + fontSize: '20px', + fontWeight: 'bold', + padding: theme.spacing(0, 0, 4, 0), + color: theme.palette.text.primary, + }, + arrowBack: { + height: '30px', + verticalAlign: 'bottom', + cursor: 'pointer', + }, + rightInputs: { + marginTop: 134, + }, + button: { + marginRight: 20 + }, + inputGrid: { + marginTop: '30px', + padding: theme.spacing(1, 0, 0, 2) + } +})) + +interface OwnProps extends RouteComponentProps { +} + +type Props = OwnProps; + +const CheckInPointForm: FunctionComponent = (props) => { + const classes = useStyles() + + const dispatch = useDispatch() + + const { + checkInPoints, + currentCheckInPoint, + checkInPointsById, + error + } = useSelector((state: RootState) => state.checkinpoints) + + const {sites} = useSelector((state: RootState) => state.sites) + + const { + sitename, + device, + checkinpoint, + } = currentCheckInPoint + const inputState = currentCheckInPoint; + + const setInputState = (checkInPoint: CheckInPointInputState) => { + dispatch(setCurrentCheckInPoint(checkInPoint)); + } + + + const handleChange = (e: any) => setInputState({ + ...inputState, + [e.target.name]: e.target.value + }) + + const handleSubmit = async (e: any) => { + e.preventDefault() + dispatch(saveCheckInPoint(JSON.stringify({ + "sitename": sitename, + "device": device, + "checkinpoint": checkinpoint + }), () => setInputState(defaultInputState))) + } + + const handleSiteChange = (sitename: string) => { + setInputState({ + ...inputState, + sitename: sitename + }); + } + + useEffect(() => { + dispatch(fetchSites()) + }, [dispatch]) + + return ( + + +
+
+ props.history.push('/checkInPoints')} /> + Add Check in point +
+ + + Save + + + + + {/*
*/} + {/* */} + o.sitename)} + label="Site" + name="sitename" + onChange={(value: any) => handleSiteChange(value)} + value={sitename} /> + + + + + + + + + + + ); +}; + +export default CheckInPointForm; diff --git a/src/features/SalesAndOrganisation/CheckInPointsView.tsx b/src/features/SalesAndOrganisation/CheckInPointsView.tsx index 310dad4..b2e8ea0 100644 --- a/src/features/SalesAndOrganisation/CheckInPointsView.tsx +++ b/src/features/SalesAndOrganisation/CheckInPointsView.tsx @@ -8,6 +8,7 @@ import { CustomMenuItem } from 'components/CustomMenuItem'; import { useDispatch, useSelector } from 'react-redux'; import { RootState } from 'app/rootReducer'; import { fetchCheckInPoints } from './checkInPointSlice'; +import CustomButton from 'components/Button'; interface OwnProps {} @@ -18,21 +19,15 @@ const useStyles = makeStyles((theme: Theme) => paper: { backgroundColor: '#E7ECF6', borderRadius: theme.shape.borderRadius - 5, - marginRight: 30, + // marginRight: 30, paddingRight: 150 }, }) ) -const data = { - port: 'Gate 1', - name: 'Pesh Infotech Ph1', - device: 'Ipad Mini 78457', -} - //const columns = ['Check In ports', 'Site name', 'Device'] const columns = [ - + { id: "checkinpoint", label: 'Check In Point' @@ -55,30 +50,34 @@ const CheckInPointsView: FunctionComponent = (props) => { checkInPoints, pageCount, pageLinks, - isLoading: isLoadingVisitor, + isLoading, error } = useSelector((state: RootState) => state.checkinpoints) - let tableRows: any = [] - - for (let i = 0; i < 10; i++) { - let copy: any = tableRows - tableRows = [data, ...copy] - } - const TableConfig = { columns: columns, + isLoading: isLoading, data: checkInPoints, pagination:true, pageChange:(page:number,count:number)=>{ dispatch(fetchCheckInPoints(page,count)) }, totalCount:pageCount, - menuOptions: [{ - item: (id: any) => console.log('check out ' + id)}> - Check Out - - }] + // menuOptions: [{ + // item: (id: any) => console.log('check out ' + id)}> + // Delete + // + // }, + // { + // item: (id: any) => console.log('check out ' + id)}> + // Disable + // + // }, + // { + // item: (id: any) => console.log('check out ' + id)}> + // View Details + // + // }] } useEffect(() => { @@ -86,14 +85,20 @@ const CheckInPointsView: FunctionComponent = (props) => { }, [dispatch]) return ( - + - - - + +