diff --git a/frontend/occupi-web/bun.lockb b/frontend/occupi-web/bun.lockb index eb0ce197..063964ba 100644 Binary files a/frontend/occupi-web/bun.lockb and b/frontend/occupi-web/bun.lockb differ diff --git a/frontend/occupi-web/package.json b/frontend/occupi-web/package.json index 0ba75526..847e083d 100644 --- a/frontend/occupi-web/package.json +++ b/frontend/occupi-web/package.json @@ -27,6 +27,7 @@ "@nextui-org/use-infinite-scroll": "^2.1.5", "@passwordless-id/webauthn": "^1.6.1", "@radix-ui/react-checkbox": "^1.1.1", + "@react-google-maps/api": "^2.20.3", "@react-pdf/renderer": "^3.4.4", "@react-stately/data": "^3.11.6", "@react-three/drei": "^9.111.5", diff --git a/frontend/occupi-web/src/components/index.ts b/frontend/occupi-web/src/components/index.ts index 8485271b..db8a67ad 100644 --- a/frontend/occupi-web/src/components/index.ts +++ b/frontend/occupi-web/src/components/index.ts @@ -70,6 +70,9 @@ import BookingsDashboard from "./bookingsDashboardComponent/BookingsDashboard"; import HourlyPredictionGraph from "./aiDashboard/aiDashGraphs/HourlyPredictionGraph"; import HourlyComparisonGraph from "./aiDashboard/aiDashGraphs/HourlyComparisonGraph"; import RecommendationsModal from "./recommendationModal/recommendationModal"; +import DeleteIPModal from './modal/DeleteIPModal'; +import AddIPModal from './modal/AddIPModal'; +import UnblockIPModal from './modal/UnblockIPModal'; export { DrawerComponent, @@ -142,4 +145,7 @@ export { HourlyPredictionGraph, HourlyComparisonGraph, RecommendationsModal, + DeleteIPModal, + AddIPModal, + UnblockIPModal }; diff --git a/frontend/occupi-web/src/components/modal/AddIPModal.tsx b/frontend/occupi-web/src/components/modal/AddIPModal.tsx new file mode 100644 index 00000000..5fa4a9f8 --- /dev/null +++ b/frontend/occupi-web/src/components/modal/AddIPModal.tsx @@ -0,0 +1,100 @@ +import React from "react"; +import { + Input, + Button, + ModalBody, + ModalFooter, + ModalHeader, +} from "@nextui-org/react"; +import DataService from "DataService"; + +const AddIPModal = ({ + onClose, + view +}: { + onClose: () => void, + view: "whitelisted" | "blacklisted" +}) => { + const [form, setForm] = React.useState<{ + email: string; + ip: string; + }>({ email: "", ip: "" }); + + const [isLoading, setIsLoading] = React.useState(false); + const [err, setErr] = React.useState(null); + + const validateEmail = (email: string) => { + return email === "" || email.match( + /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z-0-9]+\.)+[a-zA-Z]{2,}))$/ + ); + }; + + const validateIP = (ip: string) => { + return ip === "" || ip.match( + /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/ + ); + }; + + return ( + <> + + {view === "whitelisted" ? "Add new IP address" : "Add new Blacklisted IP address"} + + + setForm({ ...form, email: e.target.value })} + /> + setForm({ ...form, ip: e.target.value })} + /> + {err &&

{err}

} +
+ + + + + + ); +}; + +export default AddIPModal; \ No newline at end of file diff --git a/frontend/occupi-web/src/components/modal/DeleteIPModal.tsx b/frontend/occupi-web/src/components/modal/DeleteIPModal.tsx new file mode 100644 index 00000000..41f3d1e9 --- /dev/null +++ b/frontend/occupi-web/src/components/modal/DeleteIPModal.tsx @@ -0,0 +1,73 @@ +import React from "react"; +import { + Button, + User, + ModalBody, + ModalFooter, + ModalHeader, +} from "@nextui-org/react"; +import DataService from "DataService"; + +type User = { + email: string; + name: string; + city: string; + region: string; + country: string; + location: string; + ipAddress: string; + blackListedIP: string; + }; + +const DeleteIPModal = ({ + selectedUser, + onClose, + }: { + selectedUser: User | null; + onClose: () => void; + }) => { + const [isLoading, setIsLoading] = React.useState(false); + const [err, setErr] = React.useState(null); + return ( + <> + + Remove IP address {selectedUser?.ipAddress} + + +

Are you sure you want to remove this IP address?

+

This will prevent {selectedUser?.email} from logging in from:

+
    {selectedUser?.city}
+
    {selectedUser?.region}
+
    {selectedUser?.country}
+

They will recieve an email notifying them of this change

+ {err &&

{err}

} +
+ + + + + + ); +} + +export default DeleteIPModal \ No newline at end of file diff --git a/frontend/occupi-web/src/components/modal/UnblockIPModal.tsx b/frontend/occupi-web/src/components/modal/UnblockIPModal.tsx new file mode 100644 index 00000000..025d3858 --- /dev/null +++ b/frontend/occupi-web/src/components/modal/UnblockIPModal.tsx @@ -0,0 +1,68 @@ +import React from "react"; +import { + Button, + User, + ModalBody, + ModalFooter, + ModalHeader, +} from "@nextui-org/react"; +import DataService from "DataService"; + +type User = { + email: string; + name: string; + city: string; + region: string; + country: string; + location: string; + ipAddress: string; + blackListedIP: string; + }; + +const UnblockIPModal = ({ + selectedUser, + onClose, + }: { + selectedUser: User | null; + onClose: () => void; + }) => { + const [isLoading, setIsLoading] = React.useState(false); + const [err, setErr] = React.useState(null); + + return ( + <> + + Add new IP address + + +

Are you sure you want to allow this IP address?

+

This will allow {selectedUser?.email} to use
    {selectedUser?.blackListedIP}
to login

+

They will recieve an email notifying them of this change

+ {err &&

{err}

} +
+ + + + + + ); + }; + + export default UnblockIPModal; \ No newline at end of file diff --git a/frontend/occupi-web/src/components/sideNavComponent/SideNav.tsx b/frontend/occupi-web/src/components/sideNavComponent/SideNav.tsx index 793ac3ae..08e49473 100644 --- a/frontend/occupi-web/src/components/sideNavComponent/SideNav.tsx +++ b/frontend/occupi-web/src/components/sideNavComponent/SideNav.tsx @@ -53,7 +53,7 @@ const sidebarcontent = [ }, { icon: Location, - text: "IP addresses", + text: "Location", }, { icon: Report, @@ -92,7 +92,7 @@ const SideNav = () => { else if (arg === "Booking Statistics") navigate("/booking-statistics/overview"); else if (arg === "Company Statistics") navigate("/worker-dashboard"); else if (arg === "Employees") navigate("/employees"); - else if (arg === "IP addresses") navigate("/user-locations"); + else if (arg === "Location") navigate("/user-locations"); else; } @@ -112,7 +112,7 @@ const SideNav = () => { else if (pn.startsWith("/booking-statistics")) setSelectedPanel("Booking Statistics"); else if (pn.startsWith("/worker-dashboard")) setSelectedPanel("Company Statistics"); else if (pn.startsWith("/employees")) setSelectedPanel("Employees"); - else if (pn.startsWith("/user-locations")) setSelectedPanel("IP addresses"); + else if (pn.startsWith("/user-locations")) setSelectedPanel("Location"); else setSelectedPanel(""); }; diff --git a/frontend/occupi-web/src/pages/Locations-page/LocationPage.tsx b/frontend/occupi-web/src/pages/Locations-page/LocationPage.tsx index 2981a49e..e83d95c7 100644 --- a/frontend/occupi-web/src/pages/Locations-page/LocationPage.tsx +++ b/frontend/occupi-web/src/pages/Locations-page/LocationPage.tsx @@ -9,20 +9,17 @@ import { Input, Button, User, - Selection, Code, Spinner, Modal, - ModalBody, ModalContent, - ModalFooter, - ModalHeader, useDisclosure, } from "@nextui-org/react"; import { SearchIcon, DeleteIcon, Reload } from "@assets/index"; import DataService from "DataService"; import { motion } from "framer-motion"; import { TopNav } from "@components/index"; +import {DeleteIPModal, AddIPModal, UnblockIPModal} from "@components/index"; type User = { email: string; @@ -69,197 +66,8 @@ const BLACKLISTEDHEAD = [ }, ] -const DeleteIPModal = ({ - selectedUser, - onClose, -}: { - selectedUser: User | null; - onClose: () => void; -}) => { - const [isLoading, setIsLoading] = React.useState(false); - const [err, setErr] = React.useState(null); - return ( - <> - - Remove IP address {selectedUser?.ipAddress} - - -

Are you sure you want to remove this IP address?

-

This will prevent {selectedUser?.email} from logging in from:

-
    {selectedUser?.city}
-
    {selectedUser?.region}
-
    {selectedUser?.country}
-

They will recieve an email notifying them of this change

- {err &&

{err}

} -
- - - - - - ); -}; - -const AddIPModal = ({ - onClose, - view -}: { - onClose: () => void, - view: "whitelisted" | "blacklisted" -}) => { - const [form, setForm] = React.useState<{ - email: string; - ip: string; - }>({ email: "", ip: "" }); - - const [isLoading, setIsLoading] = React.useState(false); - const [err, setErr] = React.useState(null); - - const validateEmail = (email: string) => { - return email.match( - /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z-0-9]+\.)+[a-zA-Z]{2,}))$/ - ); - }; - - const validateIP = (ip: string) => { - return ip.match( - /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/ - ); - }; - - return ( - <> - - {view === "whitelisted" ? "Add new IP address" : "Add new Blacklisted IP address"} - - - setForm({ ...form, email: e.target.value })} - /> - setForm({ ...form, ip: e.target.value })} - /> - {err &&

{err}

} -
- - - - - - ); -}; - -const UnblockIPModal = ({ - selectedUser, - onClose, -}: { - selectedUser: User | null; - onClose: () => void; -}) => { - const [isLoading, setIsLoading] = React.useState(false); - const [err, setErr] = React.useState(null); - - return ( - <> - - Add new IP address - - -

Are you sure you want to allow this IP address?

-

This will allow {selectedUser?.email} to use
    {selectedUser?.blackListedIP}
to login

-

They will recieve an email notifying them of this change

- {err &&

{err}

} -
- - - - - - ); -}; - const LocationPage = () => { const [filterValue, setFilterValue] = React.useState(""); - const [selectedKeys, setSelectedKeys] = React.useState( - new Set([]) - ); const [users, setUsers] = React.useState([]); const [isLoading, setIsLoading] = React.useState(true); const [selectedUser, setSelectedUser] = React.useState(null); @@ -494,11 +302,8 @@ const LocationPage = () => { classNames={{ wrapper: "max-h-[65vh]", }} - selectedKeys={selectedKeys} - selectionMode="multiple" topContent={topContent} topContentPlacement="outside" - onSelectionChange={setSelectedKeys} > {(column) => (