diff --git a/src/components/AddEditCategoryModal/index.tsx b/src/components/AddEditCategoryModal/index.tsx index 521bbba..a28e32c 100644 --- a/src/components/AddEditCategoryModal/index.tsx +++ b/src/components/AddEditCategoryModal/index.tsx @@ -185,44 +185,51 @@ const AddEditCategoryModal: React.FC = ({ }} render={({ field }) => ( <> - - - - setShowPassword((prev) => !prev) - } > - {showPassword ? ( - - ) : ( - - )} - + + + setShowPassword((prev) => !prev) + } + > + {showPassword ? ( + + ) : ( + + )} + )} diff --git a/src/components/AddVehicleModal/index.tsx b/src/components/AddVehicleModal/index.tsx new file mode 100644 index 0000000..8c84bfe --- /dev/null +++ b/src/components/AddVehicleModal/index.tsx @@ -0,0 +1,196 @@ +import { useState } from "react"; +import { + Box, + Button, + Typography, + TextField, + Modal, + IconButton, +} from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; + +export default function AddVehicleModal({ + open, + handleClose, + handleAddVehicle, +}) { + // State for input fields + const [name, setName] = useState(""); + const [company, setCompany] = useState(""); + const [modelName, setModelName] = useState(""); + const [chargeType, setChargeType] = useState(""); + const [imageUrl, setImageUrl] = useState(""); + + const handleSubmit = () => { + if (!name || !company || !modelName || !chargeType || !imageUrl) { + alert("Please fill all fields"); + return; + } + + const newVehicle = { + name, + company, + modelName, + chargeType, + imageUrl, + }; + + handleAddVehicle(newVehicle); // Add vehicle to table + handleClose(); // Close modal after adding + }; + + return ( + + + {/* Header */} + + + Add Vehicle + + + + + + + {/* Horizontal Line */} + + + {/* Input Fields */} + + {/* First Row - Two Inputs */} + + + + Vehicle Name + + setName(e.target.value)} + /> + + + + + Company + + setCompany(e.target.value)} + /> + + + + {/* Second Row - Two Inputs */} + + + + Model Name + + setModelName(e.target.value)} + /> + + + + + Charge Type + + setChargeType(e.target.value)} + /> + + + + {/* Third Row - Image URL */} + + + Image URL + + setImageUrl(e.target.value)} + /> + + + + {/* Submit Button */} + + + + + + ); +} diff --git a/src/components/CustomTable/index.tsx b/src/components/CustomTable/index.tsx index 0f24bd7..a819f2f 100644 --- a/src/components/CustomTable/index.tsx +++ b/src/components/CustomTable/index.tsx @@ -9,6 +9,8 @@ import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; import Paper, { paperClasses } from "@mui/material/Paper"; import { adminList, deleteAdmin } from "../../redux/slices/adminSlice"; +import { vehicleList, deleteVehicle } from "../../redux/slices/VehicleSlice"; + import { useDispatch } from "react-redux"; import { Box, @@ -24,6 +26,8 @@ import MoreHorizRoundedIcon from "@mui/icons-material/MoreHorizRounded"; import DeleteModal from "../Modals/DeleteModal"; import { AppDispatch } from "../../redux/store/store"; import ViewModal from "../Modals/ViewModal"; +import VehicleViewModal from "../Modals/VehicleViewModal"; + import SearchIcon from "@mui/icons-material/Search"; import TuneIcon from "@mui/icons-material/Tune"; @@ -95,6 +99,8 @@ const CustomTable: React.FC = ({ const [currentPage, setCurrentPage] = React.useState(1); const usersPerPage = 10; + + const open = Boolean(anchorEl); const handleClick = (event: React.MouseEvent, row: Row) => { @@ -114,17 +120,45 @@ const CustomTable: React.FC = ({ return false; }; + + const handleDeleteButton = (id: string | undefined) => { if (!id) console.error("ID not found", id); - dispatch(deleteAdmin(id || "")); + switch (tableType) { + case "admin": + dispatch(deleteAdmin(id || "")); + break; + case "vehicle": + dispatch(deleteVehicle(id || "")); + break; + case "manager": + dispatch(deleteManager(id || "")); + break; + default: + console.error("Unknown table type:", tableType); + return; + } setDeleteModal(false); // Close the modal only after deletion handleClose(); }; - + const handleViewButton = (id: string | undefined) => { if (!id) console.error("ID not found", id); - + switch (tableType) { + case "admin": + dispatch(adminList()); + break; + case "vehicle": + dispatch(vehicleList()); + break; + case "manager": + dispatch(managerList()); + break; + default: + console.error("Unknown table type:", tableType); + return; + } dispatch(adminList()); setViewModal(false); }; @@ -433,7 +467,7 @@ const filteredRows = rows.filter( > View - {viewModal && ( + {viewModal && tableType === "admin" && ( handleViewButton(selectedRow?.id) @@ -443,6 +477,16 @@ const filteredRows = rows.filter( id={selectedRow?.id} /> )} + {viewModal && tableType === "vehicle" && ( + + handleViewButton(selectedRow?.id) + } + open={viewModal} + setViewModal={setViewModal} + id={selectedRow?.id} + /> + )} + + + + ); +}; + +export default EditVehicleModal; diff --git a/src/components/Modals/VehicleViewModal/index.tsx b/src/components/Modals/VehicleViewModal/index.tsx new file mode 100644 index 0000000..a34c57c --- /dev/null +++ b/src/components/Modals/VehicleViewModal/index.tsx @@ -0,0 +1,128 @@ +import React, { useEffect, useState } from "react"; +import { Box, Modal, Typography, Divider } from "@mui/material"; +import CloseIcon from "@mui/icons-material/Close"; +import { useSelector } from "react-redux"; +import { RootState } from "../../../redux/reducers"; + + + +type Props = { + open: boolean; + setViewModal: Function; + handleView: (id: string | undefined) => void; + id?: number | undefined; +}; +; + +const style = { + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: 400, + bgcolor: "background.paper", + borderRadius: 2, + boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.15)", + p: 4, + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: 2, +}; + +export default function VehicleViewModal({ + open, + setViewModal, + id, + +}: Props) { +const { vehicles } = useSelector((state: RootState) => state.vehicleReducer); + const [selectedVehicle, setSelectedVehicle] = useState(null); + + useEffect(() => { + if (id) { + const vehicle = vehicles.find((vehicle) => vehicle.id === id); + setSelectedVehicle(vehicle || null); + } + }, [id, vehicles]); + + return ( + + + + + + {selectedVehicle?.name || "Vehicle"}'s Details + + setViewModal(false)} + sx={{ + cursor: "pointer", + display: "flex", + alignItems: "center", + }} + > + + + + + + + + {selectedVehicle ? ( + + + Name: {selectedVehicle.name} + + + Company: {selectedVehicle.company} + + + Model Name:{" "} + {selectedVehicle.modelName} + + + Charge Type:{" "} + {selectedVehicle.chargeType} + + + Image URL:{" "} + {selectedVehicle.imageUrl} + + + ) : ( + + No vehicle found with this ID + + )} + + + ); +} diff --git a/src/components/OptionsMenu/index.tsx b/src/components/OptionsMenu/index.tsx index 42a89f9..cf1a130 100644 --- a/src/components/OptionsMenu/index.tsx +++ b/src/components/OptionsMenu/index.tsx @@ -25,7 +25,7 @@ export default function OptionsMenu({ avatar }: { avatar?: boolean }) { return ( - + { return config; }); +http.interceptors.response.use( + (response) => response, + (error) => { + if (error.response && error.response.status === 401) { + + window.location.href = "/login"; + + // const history = useHistory(); + // history.push("/login"); + } + return Promise.reject(error); + } +); export default http; diff --git a/src/pages/Auth/Login/ForgotPassword.tsx b/src/pages/Auth/Login/ForgotPassword.tsx index 83448f9..d2d9d1c 100644 --- a/src/pages/Auth/Login/ForgotPassword.tsx +++ b/src/pages/Auth/Login/ForgotPassword.tsx @@ -14,44 +14,49 @@ interface ForgotPasswordProps { export default function ForgotPassword({ open, handleClose }: ForgotPasswordProps) { return ( - ) => { - event.preventDefault(); - handleClose(); - }, - sx: { backgroundImage: 'none' }, - }} - > - Reset password - - - Enter your account's email address, and we'll send you a link to - reset your password. - - - - - - - - + ) => { + event.preventDefault(); + handleClose(); + }, + sx: { backgroundImage: "none" }, + }} + > + Reset password + + + Enter your account's email address, and we'll send + you a link to reset your password. + + + + + + + + ); } diff --git a/src/pages/Auth/Login/index.tsx b/src/pages/Auth/Login/index.tsx index cf478df..3da495f 100644 --- a/src/pages/Auth/Login/index.tsx +++ b/src/pages/Auth/Login/index.tsx @@ -47,15 +47,15 @@ export default function Login(props: { disableCustomTheme?: boolean }) { }; const onSubmit: SubmitHandler = async (data: ILoginForm) => { - try { - const response = await dispatch(loginUser(data)).unwrap(); - if (response?.data?.token) { - router("/panel/dashboard"); - } - } catch (error: any) { - console.log("Login failed:", error); + try { + const response = await dispatch(loginUser(data)).unwrap(); + if (response?.data?.token) { + router("/panel/dashboard"); } - }; + } catch (error: any) { + console.log("Login failed:", error); + } +}; return ( diff --git a/src/pages/VehicleList/index.tsx b/src/pages/VehicleList/index.tsx index 2f49cec..6f240f5 100644 --- a/src/pages/VehicleList/index.tsx +++ b/src/pages/VehicleList/index.tsx @@ -12,55 +12,18 @@ import { updateVehicle, vehicleList, } from "../../redux/slices/VehicleSlice"; -import SearchIcon from "@mui/icons-material/Search"; -const categoryRows = [ - { - srno: 1, - id: 1, // Using a number for 'id' - name: "Tesla Model S", - brand: "Tesla", - imageUrl: - "https://example.com/https://imgd-ct.aeplcdn.com/1056x660/n/cw/ec/93821/model-s-exterior-front-view.jpeg?q=80.jpg", - }, - { - srno: 2, - id: 2, - name: "BMW X5", - brand: "BMW", - imageUrl: "https://example.com/bmw_x5.jpg", - }, - { - srno: 3, - id: 3, - name: "Audi A6", - brand: "Audi", - imageUrl: "https://example.com/audi_a6.jpg", - }, - { - srno: 4, - id: 4, - name: "Mercedes-Benz S-Class", - brand: "Mercedes-Benz", - imageUrl: "https://example.com/mercedes_s_class.jpg", - }, - { - srno: 5, - id: 5, - name: "Ford Mustang", - brand: "Ford", - imageUrl: "https://example.com/ford_mustang.jpg", - }, -]; - +import AddVehicleModal from "../../components/AddVehicleModal"; +import EditVehicleModal from "../../components/EditVehicleModal"; export default function VehicleList() { - const [modalOpen, setModalOpen] = useState(false); + const [addModalOpen, setAddModalOpen] = useState(false); + const [editModalOpen, setEditModalOpen] = useState(false); const [editRow, setEditRow] = useState(null); const { reset } = useForm(); - const [deleteModal, setDeleteModal] = React.useState(false); - const [viewModal, setViewModal] = React.useState(false); - const [rowData, setRowData] = React.useState(null); + const [deleteModal, setDeleteModal] = useState(false); + const [viewModal, setViewModal] = useState(false); + const [rowData, setRowData] = useState(null); const [searchTerm, setSearchTerm] = useState(""); const dispatch = useDispatch(); const vehicles = useSelector( @@ -73,32 +36,38 @@ export default function VehicleList() { const handleClickOpen = () => { setRowData(null); // Reset row data when opening for new admin - setModalOpen(true); + setAddModalOpen(true); }; const handleCloseModal = () => { - setModalOpen(false); + setAddModalOpen(false); + setEditModalOpen(false); setRowData(null); reset(); }; - const handleCreate = async (data: { - name: string; - brand: string; + const handleAddVehicle = async (data: { + vehicleName: string; + company: string; + modelName: string; + chargeType: string; imageUrl: string; }) => { try { - await dispatch(addVehicle(data)); - await dispatch(vehicleList()); - handleCloseModal(); + await dispatch(addVehicle(data)); // Dispatch action to add vehicle + await dispatch(vehicleList()); // Fetch the updated list + handleCloseModal(); // Close the modal } catch (error) { - console.error("Creation failed", error); + console.error("Error adding vehicle", error); } }; + const handleUpdate = async ( id: number, name: string, - brand: string, + company: string, + modelName: string, + chargeType: string, imageUrl: string ) => { try { @@ -106,53 +75,70 @@ export default function VehicleList() { updateVehicle({ id, name, - brand, + company, + modelName, + chargeType, imageUrl, }) ); await dispatch(vehicleList()); + handleCloseModal(); } catch (error) { console.error("Update failed", error); } }; + const categoryColumns: Column[] = [ { id: "srno", label: "Sr No" }, { id: "name", label: "Vehicle Name" }, - { id: "brand", label: "Brand" }, + { id: "company", label: "Company" }, + { id: "modelName", label: "Model Name" }, + { id: "chargeType", label: "Charge Type" }, { id: "imageUrl", label: "Image" }, { id: "action", label: "Action", align: "center" }, ]; const filteredVehicles = vehicles?.filter( (vehicle) => - vehicle.name.toLowerCase().includes(searchTerm.toLowerCase()) || - vehicle.brand.toLowerCase().includes(searchTerm.toLowerCase()) + vehicle.name?.toLowerCase().includes(searchTerm.toLowerCase()) || + vehicle.company?.toLowerCase().includes(searchTerm.toLowerCase()) || + vehicle.modelName + ?.toLowerCase() + .includes(searchTerm.toLowerCase()) || + vehicle.chargeType + ?.toLowerCase() + .includes(searchTerm.toLowerCase()) || + vehicle.imageUrl?.toLowerCase().includes(searchTerm.toLowerCase()) ); -// const categoryRows = filteredVehicles?.length -// ? filteredVehicles?.map( -// ( -// vehicle: { -// id: number; -// name: string; -// brand: string; -// imageUrl: string; -// }, -// index: number -// ) => ({ -// id: vehicle?.id, -// srno: index + 1, -// name: vehicle?.name, -// brand: vehicle?.brand, -// imageUrl: vehicle?.imageUrl, -// }) -// ) -// : []; + const categoryRows = filteredVehicles?.length + ? filteredVehicles?.map( + ( + vehicle: { + id: number; + name: string; + company: string; + modelName: string; + chargeType: string; + imageUrl: string; + }, + index: number + ) => ({ + id: vehicle?.id, + srno: index + 1, + name: vehicle?.name, + company: vehicle?.company, + modelName: vehicle?.modelName, + chargeType: vehicle?.chargeType, + imageUrl: vehicle?.imageUrl, + }) + ) + : []; + + return ( <> - - setEditModalOpen(true)} tableType="vehicle" handleClickOpen={handleClickOpen} /> - {/* - */} + + + ); } diff --git a/src/redux/slices/VehicleSlice.ts b/src/redux/slices/VehicleSlice.ts index 9db0869..e637526 100644 --- a/src/redux/slices/VehicleSlice.ts +++ b/src/redux/slices/VehicleSlice.ts @@ -3,14 +3,15 @@ import http from "../../lib/https"; import { toast } from "sonner"; interface Vehicle { - id:number; - name:string; - brand:string; - imageUrl:string; - + id: number; + name: string; + company: string; + modelName: string; + chargeType: string; + imageUrl: string; } interface VehicleState { - vehicles:Vehicle[]; + vehicles: Vehicle[]; loading: boolean; error: string | null; } @@ -20,39 +21,42 @@ const initialState: VehicleState = { error: null, }; -export const vehicleList = createAsyncThunk( - "fetchVehicles", - async (_, { rejectWithValue }) => { - try { - const token = localStorage?.getItem("authToken"); - if (!token) throw new Error("No token found"); +export const vehicleList = createAsyncThunk< + Vehicle, + void, + { rejectValue: string } +>("fetchVehicles", async (_, { rejectWithValue }) => { + try { + const token = localStorage?.getItem("authToken"); + if (!token) throw new Error("No token found"); - const response = await http.get("/"); + const response = await http.get("/get-vehicles"); - if (!response.data?.data) throw new Error("Invalid API response"); + if (!response.data?.data) throw new Error("Invalid API response"); - return response.data.data; - } catch (error: any) { - toast.error("Error Fetching Profile" + error); - return rejectWithValue( - error?.response?.data?.message || "An error occurred" - ); - } + return response.data.data; + } catch (error: any) { + toast.error("Error Fetching Profile" + error); + return rejectWithValue( + error?.response?.data?.message || "An error occurred" + ); } -); +}); //Add Vehicle export const addVehicle = createAsyncThunk< Vehicle, { name: string; - brand: string; + company: string; + modelName: string; + chargeType: string; imageUrl: string; }, { rejectValue: string } >("/AddVehicle", async (data, { rejectWithValue }) => { try { - const response = await http.post("/", data); + const response = await http.post("create-vehicle", data); return response.data; } catch (error: any) { return rejectWithValue( @@ -61,13 +65,15 @@ export const addVehicle = createAsyncThunk< } }); - // Update Vehicle details export const updateVehicle = createAsyncThunk( "updateVehicle", async ({ id, ...vehicleData }: Vehicle, { rejectWithValue }) => { try { - const response = await http.put(`/${id}`, vehicleData); + const response = await http.patch( + `${id}/update-vehicle`, + vehicleData + ); toast.success("Vehicle Deatils updated successfully"); return response?.data; } catch (error: any) { @@ -78,6 +84,23 @@ export const updateVehicle = createAsyncThunk( } } ); +export const deleteVehicle = createAsyncThunk< + string, + string, + { rejectValue: string } +>("deleteVehicle", async (id, { rejectWithValue }) => { + try { + const response = await http.delete(`/${id}/delete-vehicle`); + toast.success(response.data?.message); + return id; + } catch (error: any) { + toast.error("Error deleting the vehicle" + error); + + return rejectWithValue( + error.response?.data?.message || "An error occurred" + ); + } +}); const vehicleSlice = createSlice({ name: "vehicle", initialState, @@ -125,6 +148,18 @@ const vehicleSlice = createSlice({ }) .addCase(updateVehicle.rejected, (state) => { state.loading = false; + }) + .addCase(deleteVehicle.pending, (state) => { + state.loading = true; + }) + .addCase(deleteVehicle.fulfilled, (state, action) => { + state.loading = false; + state.vehicles = state.vehicles.filter( + (vehicle) => String(vehicle.id) !== String(action.payload) + ); + }) + .addCase(deleteVehicle.rejected, (state) => { + state.loading = false; }); }, }); diff --git a/src/redux/slices/authSlice.ts b/src/redux/slices/authSlice.ts index 549ecdf..2f0f3f2 100644 --- a/src/redux/slices/authSlice.ts +++ b/src/redux/slices/authSlice.ts @@ -90,11 +90,8 @@ const initialState: AuthState = { isAuthenticated: false, isLoading: false, // error: null, - //Eknoor singh - //date:- 12-Feb-2025 - //initial state of token set to null token: null, - role: null, // New field for role + role: null, }; const authSlice = createSlice({ @@ -144,14 +141,7 @@ const authSlice = createSlice({ } ); - // created by Jaanvi and Eknoor - //AdminList - - //Eknoor singh - //date:- 12-Feb-2025 - //Reducers for fetching profiles has been implemente }, }); -// export const { logout } = authSlice.actions; export default authSlice.reducer; diff --git a/src/shared-theme/customizations/inputs.tsx b/src/shared-theme/customizations/inputs.tsx index b384563..de02c07 100644 --- a/src/shared-theme/customizations/inputs.tsx +++ b/src/shared-theme/customizations/inputs.tsx @@ -1,445 +1,459 @@ -import * as React from 'react'; -import { alpha, Theme, Components } from '@mui/material/styles'; -import { outlinedInputClasses } from '@mui/material/OutlinedInput'; -import { svgIconClasses } from '@mui/material/SvgIcon'; -import { toggleButtonGroupClasses } from '@mui/material/ToggleButtonGroup'; -import { toggleButtonClasses } from '@mui/material/ToggleButton'; -import CheckBoxOutlineBlankRoundedIcon from '@mui/icons-material/CheckBoxOutlineBlankRounded'; -import CheckRoundedIcon from '@mui/icons-material/CheckRounded'; -import RemoveRoundedIcon from '@mui/icons-material/RemoveRounded'; -import { gray, brand } from '../themePrimitives'; +import * as React from "react"; +import { alpha, Theme, Components } from "@mui/material/styles"; +import { outlinedInputClasses } from "@mui/material/OutlinedInput"; +import { svgIconClasses } from "@mui/material/SvgIcon"; +import { toggleButtonGroupClasses } from "@mui/material/ToggleButtonGroup"; +import { toggleButtonClasses } from "@mui/material/ToggleButton"; +import CheckBoxOutlineBlankRoundedIcon from "@mui/icons-material/CheckBoxOutlineBlankRounded"; +import CheckRoundedIcon from "@mui/icons-material/CheckRounded"; +import RemoveRoundedIcon from "@mui/icons-material/RemoveRounded"; +import { gray, brand } from "../themePrimitives"; /* eslint-disable import/prefer-default-export */ export const inputsCustomizations: Components = { - MuiButtonBase: { - defaultProps: { - disableTouchRipple: true, - disableRipple: true, - }, - styleOverrides: { - root: ({ theme }) => ({ - boxSizing: 'border-box', - transition: 'all 100ms ease-in', - '&:focus-visible': { - outline: `3px solid ${alpha(theme.palette.primary.main, 0.5)}`, - outlineOffset: '2px', - }, - }), - }, - }, - MuiButton: { - styleOverrides: { - root: ({ theme }) => ({ - boxShadow: 'none', - borderRadius: (theme.vars || theme).shape.borderRadius, - textTransform: 'none', - variants: [ - { - props: { - size: 'small', - }, - style: { - height: '2.25rem', - padding: '8px 12px', - }, - }, - { - props: { - size: 'medium', - }, - style: { - height: '2.5rem', // 40px - }, - }, - { - props: { - color: 'primary', - variant: 'contained', - }, - style: { - color: 'white', - backgroundColor: gray[900], - backgroundImage: `linear-gradient(to bottom, ${gray[700]}, ${gray[800]})`, - boxShadow: `inset 0 1px 0 ${gray[600]}, inset 0 -1px 0 1px hsl(220, 0%, 0%)`, - border: `1px solid ${gray[700]}`, - '&:hover': { - backgroundImage: 'none', - backgroundColor: gray[700], - boxShadow: 'none', - }, - '&:active': { - backgroundColor: gray[800], - }, - ...theme.applyStyles('dark', { - color: 'black', - backgroundColor: gray[50], - backgroundImage: `linear-gradient(to bottom, ${gray[100]}, ${gray[50]})`, - boxShadow: 'inset 0 -1px 0 hsl(220, 30%, 80%)', - border: `1px solid ${gray[50]}`, - '&:hover': { - backgroundImage: 'none', - backgroundColor: gray[300], - boxShadow: 'none', - }, - '&:active': { - backgroundColor: gray[400], - }, - }), - }, - }, - { - props: { - color: 'secondary', - variant: 'contained', - }, - style: { - color: 'white', - backgroundColor: brand[300], - backgroundImage: `linear-gradient(to bottom, ${alpha(brand[400], 0.8)}, ${brand[500]})`, - boxShadow: `inset 0 2px 0 ${alpha(brand[200], 0.2)}, inset 0 -2px 0 ${alpha(brand[700], 0.4)}`, - border: `1px solid ${brand[500]}`, - '&:hover': { - backgroundColor: brand[700], - boxShadow: 'none', - }, - '&:active': { - backgroundColor: brand[700], - backgroundImage: 'none', - }, - }, - }, - { - props: { - variant: 'outlined', - }, - style: { - color: (theme.vars || theme).palette.text.primary, - border: '1px solid', - borderColor: gray[200], - backgroundColor: alpha(gray[50], 0.3), - '&:hover': { - backgroundColor: gray[100], - borderColor: gray[300], - }, - '&:active': { - backgroundColor: gray[200], - }, - ...theme.applyStyles('dark', { - backgroundColor: gray[800], - borderColor: gray[700], + MuiButtonBase: { + defaultProps: { + disableTouchRipple: true, + disableRipple: true, + }, + styleOverrides: { + root: ({ theme }) => ({ + boxSizing: "border-box", + transition: "all 100ms ease-in", + "&:focus-visible": { + outline: `3px solid ${alpha( + theme.palette.primary.main, + 0.5 + )}`, + outlineOffset: "2px", + }, + }), + }, + }, + MuiButton: { + styleOverrides: { + root: ({ theme }) => ({ + boxShadow: "none", + borderRadius: (theme.vars || theme).shape.borderRadius, + textTransform: "none", + variants: [ + { + props: { + size: "small", + }, + style: { + height: "2.25rem", + padding: "8px 12px", + }, + }, + { + props: { + size: "medium", + }, + style: { + height: "2.5rem", // 40px + }, + }, + { + props: { + color: "primary", + variant: "contained", + }, + style: { + color: "white", + backgroundColor: gray[900], + backgroundImage: `linear-gradient(to bottom, ${gray[700]}, ${gray[800]})`, + boxShadow: `inset 0 1px 0 ${gray[600]}, inset 0 -1px 0 1px hsl(220, 0%, 0%)`, + border: `1px solid ${gray[700]}`, + "&:hover": { + backgroundImage: "none", + backgroundColor: gray[700], + boxShadow: "none", + }, + "&:active": { + backgroundColor: gray[800], + }, + ...theme.applyStyles("dark", { + color: "black", + backgroundColor: gray[50], + backgroundImage: `linear-gradient(to bottom, ${gray[100]}, ${gray[50]})`, + boxShadow: "inset 0 -1px 0 hsl(220, 30%, 80%)", + border: `1px solid ${gray[50]}`, + "&:hover": { + backgroundImage: "none", + backgroundColor: gray[300], + boxShadow: "none", + }, + "&:active": { + backgroundColor: gray[400], + }, + }), + }, + }, + { + props: { + color: "secondary", + variant: "contained", + }, + style: { + color: "white", + backgroundColor: brand[300], + backgroundImage: `linear-gradient(to bottom, ${alpha( + brand[400], + 0.8 + )}, ${brand[500]})`, + boxShadow: `inset 0 2px 0 ${alpha( + brand[200], + 0.2 + )}, inset 0 -2px 0 ${alpha(brand[700], 0.4)}`, + border: `1px solid ${brand[500]}`, + "&:hover": { + backgroundColor: brand[700], + boxShadow: "none", + }, + "&:active": { + backgroundColor: brand[700], + backgroundImage: "none", + }, + }, + }, + { + props: { + variant: "outlined", + }, + style: { + color: (theme.vars || theme).palette.text.primary, + border: "1px solid", + borderColor: gray[200], + backgroundColor: alpha(gray[50], 0.3), + "&:hover": { + backgroundColor: gray[100], + borderColor: gray[300], + }, + "&:active": { + backgroundColor: gray[200], + }, + ...theme.applyStyles("dark", { + backgroundColor: gray[800], + borderColor: gray[700], - '&:hover': { - backgroundColor: gray[900], - borderColor: gray[600], - }, - '&:active': { - backgroundColor: gray[900], - }, - }), - }, - }, - { - props: { - color: 'secondary', - variant: 'outlined', - }, - style: { - color: brand[700], - border: '1px solid', - borderColor: brand[200], - backgroundColor: brand[50], - '&:hover': { - backgroundColor: brand[100], - borderColor: brand[400], - }, - '&:active': { - backgroundColor: alpha(brand[200], 0.7), - }, - ...theme.applyStyles('dark', { - color: brand[50], - border: '1px solid', - borderColor: brand[900], - backgroundColor: alpha(brand[900], 0.3), - '&:hover': { - borderColor: brand[700], - backgroundColor: alpha(brand[900], 0.6), - }, - '&:active': { - backgroundColor: alpha(brand[900], 0.5), - }, - }), - }, - }, - { - props: { - variant: 'text', - }, - style: { - color: gray[600], - '&:hover': { - backgroundColor: gray[100], - }, - '&:active': { - backgroundColor: gray[200], - }, - ...theme.applyStyles('dark', { - color: gray[50], - '&:hover': { - backgroundColor: gray[700], - }, - '&:active': { - backgroundColor: alpha(gray[700], 0.7), - }, - }), - }, - }, - { - props: { - color: 'secondary', - variant: 'text', - }, - style: { - color: brand[700], - '&:hover': { - backgroundColor: alpha(brand[100], 0.5), - }, - '&:active': { - backgroundColor: alpha(brand[200], 0.7), - }, - ...theme.applyStyles('dark', { - color: brand[100], - '&:hover': { - backgroundColor: alpha(brand[900], 0.5), - }, - '&:active': { - backgroundColor: alpha(brand[900], 0.3), - }, - }), - }, - }, - ], - }), - }, - }, - MuiIconButton: { - styleOverrides: { - root: ({ theme }) => ({ - boxShadow: 'none', - borderRadius: (theme.vars || theme).shape.borderRadius, - textTransform: 'none', - fontWeight: theme.typography.fontWeightMedium, - letterSpacing: 0, - color: (theme.vars || theme).palette.text.primary, - border: '1px solid ', - borderColor: gray[200], - backgroundColor: alpha(gray[50], 0.3), - '&:hover': { - backgroundColor: gray[100], - borderColor: gray[300], - }, - '&:active': { - backgroundColor: gray[200], - }, - ...theme.applyStyles('dark', { - backgroundColor: gray[800], - borderColor: gray[700], - '&:hover': { - backgroundColor: gray[900], - borderColor: gray[600], - }, - '&:active': { - backgroundColor: gray[900], - }, - }), - variants: [ - { - props: { - size: 'small', - }, - style: { - width: '2.25rem', - height: '2.25rem', - padding: '0.25rem', - [`& .${svgIconClasses.root}`]: { fontSize: '1rem' }, - }, - }, - { - props: { - size: 'medium', - }, - style: { - width: '2.5rem', - height: '2.5rem', - }, - }, - ], - }), - }, - }, - MuiToggleButtonGroup: { - styleOverrides: { - root: ({ theme }) => ({ - borderRadius: '10px', - boxShadow: `0 4px 16px ${alpha(gray[400], 0.2)}`, - [`& .${toggleButtonGroupClasses.selected}`]: { - color: brand[500], - }, - ...theme.applyStyles('dark', { - [`& .${toggleButtonGroupClasses.selected}`]: { - color: '#fff', - }, - boxShadow: `0 4px 16px ${alpha(brand[700], 0.5)}`, - }), - }), - }, - }, - MuiToggleButton: { - styleOverrides: { - root: ({ theme }) => ({ - padding: '12px 16px', - textTransform: 'none', - borderRadius: '10px', - fontWeight: 500, - ...theme.applyStyles('dark', { - color: gray[400], - boxShadow: '0 4px 16px rgba(0, 0, 0, 0.5)', - [`&.${toggleButtonClasses.selected}`]: { - color: brand[300], - }, - }), - }), - }, - }, - MuiCheckbox: { - defaultProps: { - disableRipple: true, - icon: ( - - ), - checkedIcon: , - indeterminateIcon: , - }, - styleOverrides: { - root: ({ theme }) => ({ - margin: 10, - height: 16, - width: 16, - borderRadius: 5, - border: '1px solid ', - borderColor: alpha(gray[300], 0.8), - boxShadow: '0 0 0 1.5px hsla(210, 0%, 0%, 0.04) inset', - backgroundColor: alpha(gray[100], 0.4), - transition: 'border-color, background-color, 120ms ease-in', - '&:hover': { - borderColor: brand[300], - }, - '&.Mui-focusVisible': { - outline: `3px solid ${alpha(brand[500], 0.5)}`, - outlineOffset: '2px', - borderColor: brand[400], - }, - '&.Mui-checked': { - color: 'white', - backgroundColor: brand[500], - borderColor: brand[500], - boxShadow: `none`, - '&:hover': { - backgroundColor: brand[600], - }, - }, - ...theme.applyStyles('dark', { - borderColor: alpha(gray[700], 0.8), - boxShadow: '0 0 0 1.5px hsl(210, 0%, 0%) inset', - backgroundColor: alpha(gray[900], 0.8), - '&:hover': { - borderColor: brand[300], - }, - '&.Mui-focusVisible': { - borderColor: brand[400], - outline: `3px solid ${alpha(brand[500], 0.5)}`, - outlineOffset: '2px', - }, - }), - }), - }, - }, - MuiInputBase: { - styleOverrides: { - root: { - border: 'none', - }, - input: { - '&::placeholder': { - opacity: 0.7, - color: gray[500], - }, - }, - }, - }, - MuiOutlinedInput: { - styleOverrides: { - input: { - padding: 0, - }, - root: ({ theme }) => ({ - padding: '8px 12px', - color: (theme.vars || theme).palette.text.primary, - borderRadius: (theme.vars || theme).shape.borderRadius, - border: `1px solid ${(theme.vars || theme).palette.divider}`, - backgroundColor: (theme.vars || theme).palette.background.default, - transition: 'border 120ms ease-in', - '&:hover': { - borderColor: gray[400], - }, - [`&.${outlinedInputClasses.focused}`]: { - outline: `3px solid ${alpha(brand[500], 0.5)}`, - borderColor: brand[400], - }, - ...theme.applyStyles('dark', { - '&:hover': { - borderColor: gray[500], - }, - }), - variants: [ - { - props: { - size: 'small', - }, - style: { - height: '2.25rem', - }, - }, - { - props: { - size: 'medium', - }, - style: { - height: '2.5rem', - }, - }, - ], - }), - notchedOutline: { - border: 'none', - }, - }, - }, - MuiInputAdornment: { - styleOverrides: { - root: ({ theme }) => ({ - color: (theme.vars || theme).palette.grey[500], - ...theme.applyStyles('dark', { - color: (theme.vars || theme).palette.grey[400], - }), - }), - }, - }, - MuiFormLabel: { - styleOverrides: { - root: ({ theme }) => ({ - typography: theme.typography.caption, - marginBottom: 8, - }), - }, - }, + "&:hover": { + backgroundColor: gray[900], + borderColor: gray[600], + }, + "&:active": { + backgroundColor: gray[900], + }, + }), + }, + }, + { + props: { + color: "secondary", + variant: "outlined", + }, + style: { + color: brand[700], + border: "1px solid", + borderColor: brand[200], + backgroundColor: brand[50], + "&:hover": { + backgroundColor: brand[100], + borderColor: brand[400], + }, + "&:active": { + backgroundColor: alpha(brand[200], 0.7), + }, + ...theme.applyStyles("dark", { + color: brand[50], + border: "1px solid", + borderColor: brand[900], + backgroundColor: alpha(brand[900], 0.3), + "&:hover": { + borderColor: brand[700], + backgroundColor: alpha(brand[900], 0.6), + }, + "&:active": { + backgroundColor: alpha(brand[900], 0.5), + }, + }), + }, + }, + { + props: { + variant: "text", + }, + style: { + color: gray[600], + "&:hover": { + backgroundColor: gray[100], + }, + "&:active": { + backgroundColor: gray[200], + }, + ...theme.applyStyles("dark", { + color: gray[50], + "&:hover": { + backgroundColor: gray[700], + }, + "&:active": { + backgroundColor: alpha(gray[700], 0.7), + }, + }), + }, + }, + { + props: { + color: "secondary", + variant: "text", + }, + style: { + color: brand[700], + "&:hover": { + backgroundColor: alpha(brand[100], 0.5), + }, + "&:active": { + backgroundColor: alpha(brand[200], 0.7), + }, + ...theme.applyStyles("dark", { + color: brand[100], + "&:hover": { + backgroundColor: alpha(brand[900], 0.5), + }, + "&:active": { + backgroundColor: alpha(brand[900], 0.3), + }, + }), + }, + }, + ], + }), + }, + }, + MuiIconButton: { + styleOverrides: { + root: ({ theme }) => ({ + boxShadow: "none", + borderRadius: (theme.vars || theme).shape.borderRadius, + textTransform: "none", + fontWeight: theme.typography.fontWeightMedium, + letterSpacing: 0, + color: (theme.vars || theme).palette.text.primary, + border: "1px solid ", + borderColor: gray[200], + backgroundColor: alpha(gray[50], 0.3), + "&:hover": { + backgroundColor: gray[100], + borderColor: gray[300], + }, + "&:active": { + backgroundColor: gray[200], + }, + ...theme.applyStyles("dark", { + backgroundColor: gray[800], + borderColor: gray[700], + "&:hover": { + backgroundColor: gray[900], + borderColor: gray[600], + }, + "&:active": { + backgroundColor: gray[900], + }, + }), + variants: [ + { + props: { + size: "small", + }, + style: { + width: "2.25rem", + height: "2.25rem", + padding: "0.25rem", + [`& .${svgIconClasses.root}`]: { fontSize: "1rem" }, + }, + }, + { + props: { + size: "medium", + }, + style: { + width: "2.5rem", + height: "2.5rem", + }, + }, + ], + }), + }, + }, + MuiToggleButtonGroup: { + styleOverrides: { + root: ({ theme }) => ({ + borderRadius: "10px", + boxShadow: `0 4px 16px ${alpha(gray[400], 0.2)}`, + [`& .${toggleButtonGroupClasses.selected}`]: { + color: brand[500], + }, + ...theme.applyStyles("dark", { + [`& .${toggleButtonGroupClasses.selected}`]: { + color: "#fff", + }, + boxShadow: `0 4px 16px ${alpha(brand[700], 0.5)}`, + }), + }), + }, + }, + MuiToggleButton: { + styleOverrides: { + root: ({ theme }) => ({ + padding: "12px 16px", + textTransform: "none", + borderRadius: "10px", + fontWeight: 500, + ...theme.applyStyles("dark", { + color: gray[400], + boxShadow: "0 4px 16px rgba(0, 0, 0, 0.5)", + [`&.${toggleButtonClasses.selected}`]: { + color: brand[300], + }, + }), + }), + }, + }, + MuiCheckbox: { + defaultProps: { + disableRipple: true, + icon: ( + + ), + checkedIcon: , + indeterminateIcon: ( + + ), + }, + styleOverrides: { + root: ({ theme }) => ({ + margin: 10, + height: 16, + width: 16, + borderRadius: 5, + border: "1px solid ", + borderColor: alpha(gray[300], 0.8), + boxShadow: "0 0 0 1.5px hsla(210, 0%, 0%, 0.04) inset", + backgroundColor: alpha(gray[100], 0.4), + transition: "border-color, background-color, 120ms ease-in", + "&:hover": { + borderColor: brand[300], + }, + "&.Mui-focusVisible": { + outline: `3px solid ${alpha(brand[500], 0.5)}`, + outlineOffset: "2px", + borderColor: brand[400], + }, + "&.Mui-checked": { + color: "white", + backgroundColor: brand[500], + borderColor: brand[500], + boxShadow: `none`, + "&:hover": { + backgroundColor: brand[600], + }, + }, + ...theme.applyStyles("dark", { + borderColor: alpha(gray[700], 0.8), + boxShadow: "0 0 0 1.5px hsl(210, 0%, 0%) inset", + backgroundColor: alpha(gray[900], 0.8), + "&:hover": { + borderColor: brand[300], + }, + "&.Mui-focusVisible": { + borderColor: brand[400], + outline: `3px solid ${alpha(brand[500], 0.5)}`, + outlineOffset: "2px", + }, + }), + }), + }, + }, + MuiInputBase: { + styleOverrides: { + root: { + border: "none", + }, + input: { + "&::placeholder": { + opacity: 0.7, + color: gray[500], + }, + }, + }, + }, + MuiOutlinedInput: { + styleOverrides: { + input: { + padding: 0, + }, + root: ({ theme }) => ({ + padding: "8px 12px", + color: (theme.vars || theme).palette.text.primary, + borderRadius: (theme.vars || theme).shape.borderRadius, + border: `1px solid ${(theme.vars || theme).palette.divider}`, + backgroundColor: (theme.vars || theme).palette.background + .default, + transition: "border 120ms ease-in", + "&:hover": { + borderColor: gray[400], + }, + [`&.${outlinedInputClasses.focused}`]: { + outline: `3px solid ${alpha(brand[500], 0.5)}`, + borderColor: brand[400], + }, + ...theme.applyStyles("dark", { + "&:hover": { + borderColor: gray[500], + }, + }), + variants: [ + { + props: { + size: "small", + }, + style: { + height: "2.25rem", + }, + }, + { + props: { + size: "medium", + }, + style: { + height: "2.5rem", + }, + }, + ], + }), + notchedOutline: { + border: "none", + }, + }, + }, + MuiInputAdornment: { + styleOverrides: { + root: ({ theme }) => ({ + color: (theme.vars || theme).palette.grey[500], + ...theme.applyStyles("dark", { + color: (theme.vars || theme).palette.grey[400], + }), + }), + }, + }, + MuiFormLabel: { + styleOverrides: { + root: ({ theme }) => ({ + typography: theme.typography.caption, + marginBottom: 8, + }), + }, + }, };