wip: impl crud devices
This commit is contained in:
parent
8a2a93a288
commit
5e471b7e20
|
|
@ -154,6 +154,7 @@ export interface Props extends IconButtonProps {
|
||||||
variant?: ButtonVariantProps;
|
variant?: ButtonVariantProps;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
tooltip?: boolean | ReactNode | ReactPortal;
|
tooltip?: boolean | ReactNode | ReactPortal;
|
||||||
|
href?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function IconButton(
|
function IconButton(
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
import { Outlet } from "react-router";
|
import { Outlet } from "react-router";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import { useTheme } from "@mui/material";
|
import { useTheme } from "@mui/material";
|
||||||
|
import { useAuthStore } from "../stores/authStore";
|
||||||
|
|
||||||
export default function AuthLayout() {
|
export default function AuthLayout() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const { token } = useAuthStore();
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
window.location.href = "/dashboard";
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@ import MenuItem from "@mui/material/MenuItem";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import MenuIcon from "@mui/icons-material/Menu";
|
import MenuIcon from "@mui/icons-material/Menu";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useNavigate } from "react-router";
|
import { useAuthStore } from "../../stores/authStore";
|
||||||
|
|
||||||
export default function Header({
|
export default function Header({
|
||||||
handleDrawerToggle,
|
handleDrawerToggle,
|
||||||
}: {
|
}: {
|
||||||
handleDrawerToggle: () => void;
|
handleDrawerToggle: () => void;
|
||||||
}) {
|
}) {
|
||||||
|
const { user, logout } = useAuthStore();
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
let navigate = useNavigate();
|
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
|
|
@ -25,10 +25,10 @@ export default function Header({
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLogout = () => {
|
const onLogout = async () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
|
|
||||||
navigate("/login")
|
await logout();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -61,7 +61,7 @@ export default function Header({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="subtitle1" noWrap component="div">
|
<Typography variant="subtitle1" noWrap component="div">
|
||||||
Hi, Admin
|
Hi, {user?.name || ''}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Menu
|
<Menu
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ export default function Sidebar({
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
component={Link}
|
component={Link}
|
||||||
href={menu.link}
|
href={menu.link}
|
||||||
selected={menu.link === location.pathname}
|
selected={location.pathname.startsWith(menu.link)}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<ReactSVG src={menu.icon} />
|
<ReactSVG src={menu.icon} />
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import Breadcrumbs from "@mui/material/Breadcrumbs";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import CardContent from "@mui/material/CardContent";
|
import CardContent from "@mui/material/CardContent";
|
||||||
|
import Divider from "@mui/material/Divider";
|
||||||
import Link from "@mui/material/Link";
|
import Link from "@mui/material/Link";
|
||||||
import Grid from "@mui/material/Grid2";
|
import Grid from "@mui/material/Grid2";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
|
|
@ -71,7 +72,7 @@ export default function Devices() {
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
cell: () => (
|
cell: () => (
|
||||||
<>
|
<>
|
||||||
<IconButton variant="light" color="info" >
|
<IconButton variant="text" color="secondary" >
|
||||||
<Edit variant="Bulk" color="currentColor" />
|
<Edit variant="Bulk" color="currentColor" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
|
|
@ -86,7 +87,7 @@ export default function Devices() {
|
||||||
<Typography variant="h3">Devices</Typography>
|
<Typography variant="h3">Devices</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size="auto">
|
<Grid size="auto">
|
||||||
<Button variant="contained" startIcon={<AddIcon color="inherit" />}>
|
<Button href="/devices/create" variant="contained" startIcon={<AddIcon color="inherit" />}>
|
||||||
Add New
|
Add New
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -100,8 +101,12 @@ export default function Devices() {
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Card sx={{ display: "flex" }}>
|
<Card>
|
||||||
<CardContent sx={{ flex: "1 0 auto" }}>
|
<Box sx={{ p: 2 }}>
|
||||||
|
<Typography variant="h5">List Devices</Typography>
|
||||||
|
</Box>
|
||||||
|
<Divider />
|
||||||
|
<CardContent sx={{ flex: "1 0 auto", pt: 2 }}>
|
||||||
<ReactTable
|
<ReactTable
|
||||||
data={data}
|
data={data}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
import Alert from "@mui/material/Alert";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
import Breadcrumbs from "@mui/material/Breadcrumbs";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import Card from "@mui/material/Card";
|
||||||
|
import Divider from "@mui/material/Divider";
|
||||||
|
import CardContent from "@mui/material/CardContent";
|
||||||
|
import Grid from "@mui/material/Grid2";
|
||||||
|
import Link from "@mui/material/Link";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import { Home, Save } from "@mui/icons-material";
|
||||||
|
import useTitle from "../../hooks/useTitle";
|
||||||
|
import IconButton from "../../components/IconButton";
|
||||||
|
import { Back } from "iconsax-react";
|
||||||
|
import { useParams } from "react-router";
|
||||||
|
import Form from "./Form";
|
||||||
|
import { FormEvent } from "react";
|
||||||
|
import { useDeviceStore } from "../../stores/deviceStore";
|
||||||
|
import { DeviceRequest } from "../../types/device.types";
|
||||||
|
|
||||||
|
export default function DeviceCreate() {
|
||||||
|
useTitle("Devices");
|
||||||
|
const { pid } = useParams();
|
||||||
|
const { update, create, error } = useDeviceStore();
|
||||||
|
|
||||||
|
const IS_EDIT_PAGE = pid!!;
|
||||||
|
|
||||||
|
const onSubmit = async (e: FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(e.target as HTMLFormElement);
|
||||||
|
|
||||||
|
const data = Object.fromEntries(formData.entries()) as unknown as DeviceRequest;
|
||||||
|
|
||||||
|
if (IS_EDIT_PAGE) {
|
||||||
|
await update(pid!!, data);
|
||||||
|
} else {
|
||||||
|
await create(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Box component="main">
|
||||||
|
<Grid container spacing={2} alignItems={"center"} mb={4}>
|
||||||
|
<Grid size="auto">
|
||||||
|
<Box display={"flex"} alignItems={"center"} gap={1}>
|
||||||
|
<IconButton variant="dashed" color="primary" href="/devices">
|
||||||
|
<Back variant="Outline" color="currentColor" />
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h3">{IS_EDIT_PAGE ? `Edit Device - ${pid}` : 'Create Device'}</Typography>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={12}>
|
||||||
|
<Breadcrumbs aria-label="breadcrumb">
|
||||||
|
<Link underline="hover" color="inherit" href="/dashboard">
|
||||||
|
<Home />
|
||||||
|
</Link>
|
||||||
|
<Link underline="hover" color="inherit" href="/devices">
|
||||||
|
<Typography sx={{ color: "text.primary" }}>Devices</Typography>
|
||||||
|
</Link>
|
||||||
|
<Typography sx={{ color: "text.primary" }}>{IS_EDIT_PAGE ? pid : 'Create'}</Typography>
|
||||||
|
</Breadcrumbs>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<Box display={"flex"} mb={2}>
|
||||||
|
<Alert severity="error" variant="border" sx={{ width: "100%" }}>{error.toString()} asass</Alert>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Card component="form" onSubmit={onSubmit}>
|
||||||
|
<Box
|
||||||
|
sx={{ px: 3, py: 1 }}
|
||||||
|
display={"flex"}
|
||||||
|
justifyContent={"space-between"}
|
||||||
|
alignItems={"center"}
|
||||||
|
>
|
||||||
|
<Typography variant="h5">Fill the form</Typography>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
startIcon={<Save color="inherit" />}
|
||||||
|
>
|
||||||
|
{IS_EDIT_PAGE ? "Save Changes" : "Create"}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Divider />
|
||||||
|
<CardContent>
|
||||||
|
<Form />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import Chip from '@mui/material/Chip';
|
||||||
|
import FormControl from "@mui/material/FormControl";
|
||||||
|
import Grid from "@mui/material/Grid2";
|
||||||
|
import InputLabel from "@mui/material/InputLabel";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import Select from "@mui/material/Select";
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { DeviceStatus } from '../../types/device.types';
|
||||||
|
|
||||||
|
export default function Form() {
|
||||||
|
const [select, setSelect] = useState<DeviceStatus>('active');
|
||||||
|
|
||||||
|
const STATUS = ["active", "inactive", "maintenance"];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{/* Device Code */}
|
||||||
|
<Grid size={{ md: 4, xs: 12 }}>
|
||||||
|
<TextField fullWidth name='device_code' label="Device Code" variant="outlined" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Total Port */}
|
||||||
|
<Grid size={{ md: 4, xs: 12 }}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name="port_count"
|
||||||
|
label="Total Port"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Status */}
|
||||||
|
<Grid size={{ md: 4, xs: 12 }}>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel id="status-label">Status</InputLabel>
|
||||||
|
<Select
|
||||||
|
name="status"
|
||||||
|
labelId="status-label"
|
||||||
|
label="Status"
|
||||||
|
value={select}
|
||||||
|
onChange={(e) => setSelect(e.target.value as DeviceStatus)}
|
||||||
|
renderValue={(selected: string) => (
|
||||||
|
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
|
||||||
|
<Chip
|
||||||
|
label={selected.toUpperCase()}
|
||||||
|
size="medium"
|
||||||
|
variant="filled"
|
||||||
|
color={
|
||||||
|
selected === "active"
|
||||||
|
? "success"
|
||||||
|
: selected === "inactive"
|
||||||
|
? "error"
|
||||||
|
: "warning"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{STATUS.map((status) => (
|
||||||
|
<MenuItem key={status} value={status}>
|
||||||
|
{status.toUpperCase()}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ md: 6, xs: 12 }}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name="longitude"
|
||||||
|
label="Longitude"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid size={{ md: 6, xs: 12 }}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
name="latitude"
|
||||||
|
label="Latitude"
|
||||||
|
variant="outlined"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -5,11 +5,23 @@ const api = createAPI();
|
||||||
|
|
||||||
export const authRepository = {
|
export const authRepository = {
|
||||||
async login(payload: LoginPayload): Promise<LoginResponse> {
|
async login(payload: LoginPayload): Promise<LoginResponse> {
|
||||||
const response = await api.post<LoginResponse>('/auth/login', payload);
|
// const response = await api.post<LoginResponse>('/auth/login', payload);
|
||||||
return response.data;
|
|
||||||
|
// return response.data;
|
||||||
|
return Promise.resolve({
|
||||||
|
status: {
|
||||||
|
code: 200,
|
||||||
|
description: 'OK',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
token: 'sample-token',
|
||||||
|
user: {
|
||||||
|
name: 'John Doe',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async logout(): Promise<void> {
|
async logout(): Promise<void> {
|
||||||
await api.post('/auth/logout');
|
await api.post('/auth/logout');
|
||||||
},
|
},};
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { createAPI } from "../services/api";
|
||||||
|
import { DeviceRepositoryProps, Device } from "../types/device.types";
|
||||||
|
import { ResponseApi } from "../types/response.types";
|
||||||
|
|
||||||
|
const api = createAPI();
|
||||||
|
|
||||||
|
export const deviceRepository: DeviceRepositoryProps = {
|
||||||
|
async getAll() {
|
||||||
|
const response = await api.get<ResponseApi<Device[]>>("/api/v1/devices");
|
||||||
|
|
||||||
|
return response.data.data as Device[];
|
||||||
|
},
|
||||||
|
|
||||||
|
async getDeviceById(id: string) {
|
||||||
|
const response = await api.get<ResponseApi<Device>>(`/api/v1/devices/${id}`);
|
||||||
|
|
||||||
|
return response.data.data as Device;
|
||||||
|
},
|
||||||
|
|
||||||
|
async createDevice(data: Device) {
|
||||||
|
const response = await api.post<ResponseApi<null>>("/api/v1/devices", data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async updateDevice(id: string, data: Device) {
|
||||||
|
const response = await api.put<ResponseApi<null>>(`/api/v1/devices/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -9,6 +9,7 @@ import Devices from "../pages/Devices";
|
||||||
import Fishbone from "../pages/Fishbone";
|
import Fishbone from "../pages/Fishbone";
|
||||||
import Towers from "../pages/Towers";
|
import Towers from "../pages/Towers";
|
||||||
import RequiredAuth from "./RequiredAuth";
|
import RequiredAuth from "./RequiredAuth";
|
||||||
|
import DeviceCreate from "../pages/Devices/Create";
|
||||||
|
|
||||||
export default function Routes() {
|
export default function Routes() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -28,6 +29,10 @@ export default function Routes() {
|
||||||
<Route path="/fishbone" element={<Fishbone />} />
|
<Route path="/fishbone" element={<Fishbone />} />
|
||||||
<Route path="/devices" element={<Devices />} />
|
<Route path="/devices" element={<Devices />} />
|
||||||
<Route path="/towers" element={<Towers />} />
|
<Route path="/towers" element={<Towers />} />
|
||||||
|
|
||||||
|
{/* Create Page */}
|
||||||
|
<Route path="/devices/:pid" element={<DeviceCreate />} />
|
||||||
|
<Route path="/devices/create" element={<DeviceCreate />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
</Route>
|
</Route>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { authRepository } from '../repositories/authRepository';
|
import { authRepository } from '../repositories/authRepository';
|
||||||
import { AuthState } from './types';
|
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
import { createJSONStorage } from 'zustand/middleware';
|
import { createJSONStorage } from 'zustand/middleware';
|
||||||
import { secureStorage } from './storage';
|
import { secureStorage } from './storage';
|
||||||
|
import { AuthState } from '../types/auth.types';
|
||||||
|
|
||||||
type PersistedAuthState = Pick<AuthState, 'token' | 'user'>;
|
type PersistedAuthState = Pick<AuthState, 'token' | 'user'>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { create } from "zustand";
|
||||||
|
import { deviceRepository } from "../repositories/deviceRepository";
|
||||||
|
import { persist } from "zustand/middleware";
|
||||||
|
import { createJSONStorage } from "zustand/middleware";
|
||||||
|
import { secureStorage } from "./storage";
|
||||||
|
import { Device, DeviceState } from "../types/device.types";
|
||||||
|
|
||||||
|
export const useDeviceStore = create<DeviceState>()(
|
||||||
|
persist(
|
||||||
|
(set) => ({
|
||||||
|
data: [],
|
||||||
|
device: null,
|
||||||
|
isLoading: false,
|
||||||
|
error: null,
|
||||||
|
getAll: async () => {
|
||||||
|
set({ isLoading: true });
|
||||||
|
try {
|
||||||
|
const devices = await deviceRepository.getAll();
|
||||||
|
set({ data: devices });
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.status === 401) {
|
||||||
|
set({ error: error.response.status.description });
|
||||||
|
} else {
|
||||||
|
set({ error: error.response.status.description || error.message });
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
set({ isLoading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
find: async (id: string) => {
|
||||||
|
set({ isLoading: true });
|
||||||
|
try {
|
||||||
|
const device = await deviceRepository.getDeviceById(id);
|
||||||
|
|
||||||
|
set({ device: device });
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.status === 401) {
|
||||||
|
set({ error: error.response.status.description });
|
||||||
|
} else {
|
||||||
|
set({ error: error.response?.status?.description || error.message });
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
set({ isLoading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: async (device: Omit<Device, "id" & "created_at" & "updated_at">) => {
|
||||||
|
set({ isLoading: true });
|
||||||
|
try {
|
||||||
|
await deviceRepository.createDevice(device);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
if (error.status === 401) {
|
||||||
|
set({ error: error.response.status.description });
|
||||||
|
} else {
|
||||||
|
set({ error: error.response?.status?.description || error.message });
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
set({ isLoading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update: async (id: string, device: Omit<Device, "id" & "created_at" & "updated_at">) => {
|
||||||
|
set({ isLoading: true });
|
||||||
|
try {
|
||||||
|
await deviceRepository.updateDevice(id, device);
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.status === 401) {
|
||||||
|
set({ error: error.response.status.description });
|
||||||
|
} else {
|
||||||
|
set({ error: error.response?.status?.description || error.message });
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
set({ isLoading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ name: "devices", storage: createJSONStorage(() => secureStorage) }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { LoginPayload, UserProfile } from "../types/auth.types";
|
|
||||||
|
|
||||||
export interface AuthState {
|
|
||||||
token: string | null;
|
|
||||||
user: UserProfile | null;
|
|
||||||
isLoading: boolean;
|
|
||||||
error: string | null | AuthErrorInputState;
|
|
||||||
login: (payload: LoginPayload) => Promise<boolean>;
|
|
||||||
logout: () => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthErrorInputState {
|
|
||||||
username?: string | null;
|
|
||||||
password?: string | null;
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// MATERIAL - UI
|
// MATERIAL - UI
|
||||||
import { Theme } from '@mui/material/styles';
|
import { Theme } from '@mui/material';
|
||||||
|
|
||||||
// PROJECT IMPORTS
|
// PROJECT IMPORTS
|
||||||
import getColors from '../../utils/getColors';
|
import getColors from '../../utils/getColors';
|
||||||
|
|
|
||||||
|
|
@ -17,3 +17,21 @@ export interface LoginResponse {
|
||||||
export interface UserProfile {
|
export interface UserProfile {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auth state
|
||||||
|
* ===========
|
||||||
|
*/
|
||||||
|
export interface AuthState {
|
||||||
|
token: string | null;
|
||||||
|
user: UserProfile | null;
|
||||||
|
isLoading: boolean;
|
||||||
|
error: string | null | AuthErrorInputState;
|
||||||
|
login: (payload: LoginPayload) => Promise<boolean>;
|
||||||
|
logout: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthErrorInputState {
|
||||||
|
username?: string | null;
|
||||||
|
password?: string | null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { ResponseApi } from "./response.types";
|
||||||
|
|
||||||
|
export interface DeviceRepositoryProps {
|
||||||
|
getAll: () => Promise<Device[] | []>;
|
||||||
|
getDeviceById: (id: string) => Promise<Device>;
|
||||||
|
createDevice: (device: DeviceRequest) => Promise<Pick<ResponseApi<any>, "status">>;
|
||||||
|
updateDevice: (id: string, device: DeviceRequest) => Promise<Pick<ResponseApi<any>, "status">>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Device {
|
||||||
|
id: string;
|
||||||
|
device_code: string;
|
||||||
|
device_type: string;
|
||||||
|
longitude: string | number;
|
||||||
|
latitude: string | number;
|
||||||
|
port_amount: number;
|
||||||
|
status: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DeviceStatus = "active" | "inactive" | "maintenance";
|
||||||
|
|
||||||
|
export interface DeviceRequest extends Omit<Device, "id" & "created_at" & "updated_at"> {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Device State
|
||||||
|
* =============
|
||||||
|
*/
|
||||||
|
export interface DeviceState {
|
||||||
|
data?: Device[];
|
||||||
|
device?: Device | null;
|
||||||
|
isLoading: boolean;
|
||||||
|
error: string | null | DeviceErrorInputState;
|
||||||
|
getAll: () => Promise<void>;
|
||||||
|
find: (id: string) => Promise<void>;
|
||||||
|
create: (device: DeviceRequest) => Promise<void>;
|
||||||
|
update: (id: string, device: DeviceRequest) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeviceErrorInputState {
|
||||||
|
username?: string | null;
|
||||||
|
password?: string | null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
interface ResponseApiStatus {
|
||||||
|
status: string | number;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ResponseApi<T> {
|
||||||
|
status: ResponseApiStatus;
|
||||||
|
message: string;
|
||||||
|
data?: T | [] | null;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue