diff --git a/src/components/FlashMessage.tsx b/src/components/FlashMessage.tsx
index 5d5f612..8a8187d 100644
--- a/src/components/FlashMessage.tsx
+++ b/src/components/FlashMessage.tsx
@@ -3,9 +3,10 @@ import Box from "@mui/material/Box";
import Alert from "@mui/material/Alert";
import { DeviceState } from "../types/device.types";
import { AuthState } from "../types/auth.types";
+import { FishboneState } from "../types/fishbone.types";
interface FlashMessageProps {
- store: () => DeviceState | AuthState;
+ store: () => DeviceState | AuthState | FishboneState;
}
export default function FlashMessage(props: FlashMessageProps) {
diff --git a/src/layouts/DashboardLayout.tsx b/src/layouts/DashboardLayout.tsx
index e0c96ca..a8615d5 100644
--- a/src/layouts/DashboardLayout.tsx
+++ b/src/layouts/DashboardLayout.tsx
@@ -40,7 +40,9 @@ export default function DashboardLayout(props: Props) {
[] = [
- {
- header: "Device Code",
- accessorKey: "device_code",
- },
- {
- header: "Device Type",
- accessorKey: "device_type",
- },
- {
- header: "Address",
- accessorKey: "address",
- },
- {
- header: "Total Port",
- accessorKey: "port_amount",
- },
- {
- header: "Status",
- accessorKey: "status",
- cell: ({ row }) => (
-
- {row.original.status}
-
- ),
- },
- {
- header: "",
- accessorKey: "action",
- enableSorting: false,
- cell: ({ row }) => (
- <>
-
-
-
- >
- ),
- },
- ];
+ const columns: ColumnDef[] = useMemo(
+ () => [
+ {
+ header: "Device Code",
+ accessorKey: "device_code",
+ },
+ {
+ header: "Device Type",
+ accessorKey: "device_type",
+ },
+ {
+ header: "Address",
+ accessorKey: "address",
+ },
+ {
+ header: "Total Port",
+ accessorKey: "port_amount",
+ },
+ {
+ header: "Total Used Port",
+ accessorKey: "total_used_port",
+ },
+ {
+ header: "Status",
+ accessorKey: "status",
+ cell: ({ row }) => (
+
+ {row.original.status.toUpperCase()}
+
+ ),
+ },
+ {
+ header: "",
+ accessorKey: "action",
+ enableSorting: false,
+ cell: ({ row }) => (
+ <>
+
+
+
+ >
+ ),
+ },
+ ],
+ []
+ );
useEffect(() => {
if (cacheExpired()) {
(async () => {
- await getAll()
- })()
+ await getAll();
+ })();
}
}, []);
diff --git a/src/pages/Devices/Create.tsx b/src/pages/Devices/CreateOrEdit.tsx
similarity index 98%
rename from src/pages/Devices/Create.tsx
rename to src/pages/Devices/CreateOrEdit.tsx
index 3b814cd..70776f0 100644
--- a/src/pages/Devices/Create.tsx
+++ b/src/pages/Devices/CreateOrEdit.tsx
@@ -18,7 +18,7 @@ import { useDeviceStore } from "../../stores/deviceStore";
import { DeviceRequest } from "../../types/device.types";
import FlashMessage from "../../components/FlashMessage";
-export default function DeviceCreate() {
+export default function DeviceCreateOrEdit() {
useTitle("Devices");
const { pid } = useParams();
const { update, create, isLoading, find, clearDevice, device } = useDeviceStore();
diff --git a/src/pages/Devices/Form.tsx b/src/pages/Devices/Form.tsx
index 764e5cf..4ba4a5f 100644
--- a/src/pages/Devices/Form.tsx
+++ b/src/pages/Devices/Form.tsx
@@ -1,28 +1,36 @@
-import Box from '@mui/material/Box';
-import Chip from '@mui/material/Chip';
+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 { useEffect, useState } from 'react';
-import { DeviceStatus } from '../../types/device.types';
-import { useDeviceStore } from '../../stores/deviceStore';
+import { useEffect, useState } from "react";
+import { DeviceStatus } from "../../types/device.types";
+import { useDeviceStore } from "../../stores/deviceStore";
export default function Form() {
- const { device, clearDevice } = useDeviceStore();
- const [select, setSelect] = useState('active');
+ const { device, clearDevice, towerSelect, getTowerSelect } = useDeviceStore();
+ const [select, setSelect] = useState("active");
+ const [tower, setTower] = useState("");
const STATUS = ["active", "inactive", "maintenance"];
useEffect(() => {
- setSelect(device?.status || 'active');
+ (async () => {
+ await getTowerSelect();
+ })();
+
+ if (device) {
+ setSelect(device.status);
+ setTower(device.tower_id as string);
+ }
const clear = async () => {
await clearDevice();
};
-
+
return () => {
clear();
};
@@ -30,12 +38,17 @@ export default function Form() {
return (
- {/* Device Code */}
-
-
+
+
- {/* Total Port */}
-
+
+
- {/* Status */}
-
+
+
+ Tower
+
+
+
+
+
Status
- }>
+ }
+ >
Add New
@@ -82,12 +99,15 @@ export default function Fishbone() {
-
-
-
+
+
+
+
+ List Devices
+
+
+
+
diff --git a/src/pages/Fishbone/CreateOrEdit.tsx b/src/pages/Fishbone/CreateOrEdit.tsx
new file mode 100644
index 0000000..cd49463
--- /dev/null
+++ b/src/pages/Fishbone/CreateOrEdit.tsx
@@ -0,0 +1,105 @@
+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, useEffect } from "react";
+import FlashMessage from "../../components/FlashMessage";
+import { useFishboneStore } from "../../stores/fishboneStore";
+import { FishboneRequest } from "../../types/fishbone.types";
+
+export default function FishboneCreateOrEdit() {
+ useTitle("Fishbone");
+ const { pid } = useParams();
+ const { update, create, isLoading, find, clearFishbone } = useFishboneStore();
+
+ 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 FishboneRequest;
+
+ if (IS_EDIT_PAGE) {
+ await update(pid!!, data);
+ } else {
+ await create(data);
+ }
+ }
+
+ useEffect(() => {
+ if (pid!!) {
+ (async () => {
+ await find(pid!!);
+ })()
+ } else {
+ (async () => {
+ await clearFishbone()
+ })()
+ }
+ }, [])
+
+ return (
+
+
+
+
+
+
+
+ {IS_EDIT_PAGE ? `Edit Fishbone - ${pid}` : 'Create Fishbone'}
+
+
+
+
+
+
+
+
+ Fishbone
+
+ {IS_EDIT_PAGE ? pid : 'Create'}
+
+
+
+
+
+
+
+
+ Fill the form
+ }
+ >
+ {IS_EDIT_PAGE ? "Save Changes" : "Create"}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/Fishbone/Form.tsx b/src/pages/Fishbone/Form.tsx
new file mode 100644
index 0000000..f6647ee
--- /dev/null
+++ b/src/pages/Fishbone/Form.tsx
@@ -0,0 +1,143 @@
+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 { useEffect, useState } from "react";
+import { useFishboneStore } from "../../stores/fishboneStore";
+
+export default function Form() {
+ const {
+ fishbone,
+ clearFishbone,
+ backboneSelect,
+ deviceSelect,
+ getDeviceSelect,
+ getBackboneSelect,
+ } = useFishboneStore();
+ const [backbone, setBackbone] = useState("");
+ const [deviceStart, setDeviceStart] = useState("");
+ const [deviceEnd, setDeviceEnd] = useState("");
+
+ useEffect(() => {
+ (async () => {
+ await getBackboneSelect();
+ await getDeviceSelect();
+ })();
+
+ if (fishbone) {
+ setBackbone(fishbone.backbone_id);
+ setDeviceStart(fishbone.dev_start_id);
+ setDeviceEnd(fishbone.dev_end_id);
+ }
+
+ const clear = async () => {
+ await clearFishbone();
+ };
+
+ return () => {
+ clear();
+ };
+ }, [fishbone]);
+
+ return (
+
+
+
+ Backbone
+
+
+
+
+
+ Device Start
+
+
+
+
+
+ Device End
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/repositories/deviceRepository.ts b/src/repositories/deviceRepository.ts
index 6c52f0c..a8454fa 100644
--- a/src/repositories/deviceRepository.ts
+++ b/src/repositories/deviceRepository.ts
@@ -1,6 +1,7 @@
import { createAPI } from "../services/api";
-import { DeviceRepositoryProps, Device } from "../types/device.types";
+import { DeviceRepositoryProps, Device, IGetTowerSelect } from "../types/device.types";
import { ResponseApi } from "../types/response.types";
+import { SelectState } from "../types/store.types";
const api = createAPI();
@@ -19,9 +20,9 @@ export const deviceRepository: DeviceRepositoryProps = {
latitude: "1",
address: "Jl. Jend Sudirman No. XX",
port_amount: 10,
+ total_used_port: 5,
status: "active",
created_at: "2024-01-01",
- updated_at: "2024-01-01",
}
])
},
@@ -39,6 +40,7 @@ export const deviceRepository: DeviceRepositoryProps = {
address: "Jl. Jend Sudirman No. XX",
port_amount: 10,
status: "active",
+ tower_id: null,
created_at: "2024-01-01",
updated_at: "2024-01-01",
})
@@ -53,4 +55,16 @@ export const deviceRepository: DeviceRepositoryProps = {
const response = await api.put>(`/api/v1/devices/${id}`, data);
return response.data;
},
+
+ async getTowerSelect() {
+ // const response = await api.get>("/api/v1/devices/tower-select");
+
+ // return (response.data.data as IGetTowerSelect[])?.map((i: IGetTowerSelect) => ({label: i.tower_code, value: i.id})) as SelectState[];
+ return Promise.resolve([
+ {
+ label: "TWR-EX-001",
+ value: "1",
+ }
+ ]);
+ }
};
diff --git a/src/repositories/fishboneRepository.ts b/src/repositories/fishboneRepository.ts
new file mode 100644
index 0000000..2d607e0
--- /dev/null
+++ b/src/repositories/fishboneRepository.ts
@@ -0,0 +1,89 @@
+import { createAPI } from "../services/api";
+import { FishboneRepositoryProps, Fishbone, IGetBackboneSelect } from "../types/fishbone.types";
+import { ResponseApi } from "../types/response.types";
+import { SelectState } from "../types/store.types";
+
+const api = createAPI();
+
+export const fishboneRepository: FishboneRepositoryProps = {
+ async getAll() {
+ // const response = await api.get>("/api/v1/fishbones");
+
+ // return response.data.data as Fishbone[];
+
+ return Promise.resolve([
+ {
+ id: "1",
+ backbone: "abced-efghi",
+ device_start: "DEV-S1",
+ device_end: "DEV-E1",
+ address: "Jl. Jend Sudirman No. XX",
+ core_amount: 10,
+ longitude: "1",
+ latitude: "1",
+ }
+ ])
+ },
+
+ async getFishboneById(id: string) {
+ // const response = await api.get>(`/api/v1/fishbones/${id}`);
+
+ // return response.data.data as Fishbone;
+ return Promise.resolve({
+ id: "1",
+ // fishbone_code: "DV-EX-001",
+ backbone_id: "abced-efghi",
+ backbone_core: "16",
+ dev_start_id: "1",
+ dev_end_id: "2",
+ longitude: "1",
+ latitude: "1",
+ core_amount: 10,
+ address: "Jl. Jend Sudirman No. XX",
+ created_at: "2024-01-01",
+ })
+ },
+
+ async createFishbone(data: Fishbone) {
+ const response = await api.post>("/api/v1/fishbones", data);
+ return response.data;
+ },
+
+ async updateFishbone(id: string, data: Fishbone) {
+ const response = await api.put>(`/api/v1/fishbones/${id}`, data);
+ return response.data;
+ },
+
+ async getBackboneSelect() {
+ // const response = await api.get>("/api/v1/fishbones/backbone");
+
+ // return (response.data.data as IGetBackboneSelect[])?.map((i: IGetBackboneSelect) => ({label: i.backbone_code, value: i.id})) as SelectState[];
+ return Promise.resolve([
+ {
+ label: "BB-001",
+ value: "abced-efghi",
+ },
+ {
+ label: "BB-002",
+ value: "jklmn-opqrs",
+ }
+ ]);
+ },
+
+ async getDeviceSelect() {
+ // const response = await api.get>("/api/v1/fishbones/device");
+
+ // return (response.data.data as IGetBackboneSelect[])?.map((i: IGetBackboneSelect) => ({label: i.backbone_code, value: i.id})) as SelectState[];
+
+ return Promise.resolve([
+ {
+ label: "DEV-S1",
+ value: "1",
+ },
+ {
+ label: "DEV-S2",
+ value: "2",
+ }
+ ]);
+ }
+};
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 0fcc180..1edbe3f 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -9,7 +9,8 @@ import Devices from "../pages/Devices";
import Fishbone from "../pages/Fishbone";
import Towers from "../pages/Towers";
import RequiredAuth from "./RequiredAuth";
-import DeviceCreate from "../pages/Devices/Create";
+import DeviceCreateOrEdit from "../pages/Devices/CreateOrEdit";
+import FishboneCreateOrEdit from "../pages/Fishbone/CreateOrEdit";
export default function Routes() {
return (
@@ -31,8 +32,11 @@ export default function Routes() {
} />
{/* Create Page */}
- } />
- } />
+ } />
+ } />
+
+ } />
+ } />
diff --git a/src/stores/deviceStore.ts b/src/stores/deviceStore.ts
index a188eca..d1dac75 100644
--- a/src/stores/deviceStore.ts
+++ b/src/stores/deviceStore.ts
@@ -15,6 +15,7 @@ export const useDeviceStore = create()(
isLoading: false,
error: null,
lastUpdate: null,
+ towerSelect: [],
getAll: async () => {
set({ isLoading: true });
try {
@@ -89,6 +90,23 @@ export const useDeviceStore = create()(
set({ isLoading: false });
}
},
+ getTowerSelect: async () => {
+ set({ isLoading: true });
+ try {
+ const towers = await deviceRepository.getTowerSelect();
+ set({ towerSelect: towers });
+ } 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 });
+ }
+ },
clearError: () => set({ error: null }),
clearDevice: () => {
set({ device: null })
diff --git a/src/stores/fishboneStore.ts b/src/stores/fishboneStore.ts
new file mode 100644
index 0000000..d3f970a
--- /dev/null
+++ b/src/stores/fishboneStore.ts
@@ -0,0 +1,146 @@
+import { create } from "zustand";
+import { persist } from "zustand/middleware";
+import { fishboneRepository } from "../repositories/fishboneRepository";
+import { createJSONStorage } from "zustand/middleware";
+import { immer } from 'zustand/middleware/immer'
+import { secureStorage } from "./storage";
+import { Fishbone, FishboneState } from "../types/fishbone.types";
+import dayjs from "dayjs";
+
+export const useFishboneStore = create()(
+ persist(
+ immer((set, get) => ({
+ data: [],
+ fishbone: null,
+ isLoading: false,
+ error: null,
+ lastUpdate: null,
+ backboneSelect: [],
+ deviceSelect: [],
+ getAll: async () => {
+ set({ isLoading: true });
+ try {
+ const fishbones = await fishboneRepository.getAll();
+ set({ data: fishbones, lastUpdate: dayjs().valueOf() });
+ } 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, lastUpdate: dayjs().valueOf() });
+ }
+ },
+ find: async (id: string) => {
+ set({ isLoading: true });
+ try {
+ const fishbone = await fishboneRepository.getFishboneById(id);
+
+ set({ fishbone: fishbone });
+ } 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 (
+ fishbone: Omit
+ ) => {
+ set({ isLoading: true });
+ try {
+ await fishboneRepository.createFishbone(fishbone);
+ } 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,
+ fishbone: Omit
+ ) => {
+ set({ isLoading: true });
+ try {
+ await fishboneRepository.updateFishbone(id, fishbone);
+ } 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 });
+ }
+ },
+ getBackboneSelect: async () => {
+ set({ isLoading: true });
+ try {
+ const backboneSelect = await fishboneRepository.getBackboneSelect();
+ set({ backboneSelect: backboneSelect });
+ } 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 });
+ }
+ },
+ getDeviceSelect: async () => {
+ set({ isLoading: true });
+ try {
+ const deviceSelect = await fishboneRepository.getDeviceSelect();
+ set({ deviceSelect: deviceSelect });
+ } 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 });
+ }
+ },
+ clearError: () => set({ error: null }),
+ clearFishbone: () => {
+ set({ fishbone: null })
+ },
+ cacheExpired: () => {
+ return (
+ get().lastUpdate === null ||
+ dayjs(get().lastUpdate).isBefore(
+ dayjs().subtract(
+ import.meta.env.VITE_APP_CACHE_TIME_VALUE,
+ import.meta.env.VITE_APP_CACHE_TIME_UNIT
+ )
+ )
+ );
+ },
+ })),
+ { name: "fishbones", storage: createJSONStorage(() => secureStorage) }
+ )
+);
diff --git a/src/theme/components/index.ts b/src/theme/components/index.ts
index 3c3cc7b..b276aad 100644
--- a/src/theme/components/index.ts
+++ b/src/theme/components/index.ts
@@ -96,7 +96,7 @@ export default function ComponentsOverrides(theme: Theme) {
TableFooter(theme),
TableHead(theme),
TablePagination(),
- TableRow(),
+ TableRow(theme),
Tabs(),
ToggleButton(theme),
Tooltip(theme),
diff --git a/src/types/device.types.ts b/src/types/device.types.ts
index ccd33ca..56a514f 100644
--- a/src/types/device.types.ts
+++ b/src/types/device.types.ts
@@ -1,11 +1,12 @@
import { ResponseApi } from "./response.types";
-import { CacheState, ErrorState } from "./store.types";
+import { CacheState, ErrorState, SelectState } from "./store.types";
export interface DeviceRepositoryProps {
- getAll: () => Promise;
+ getAll: () => Promise;
getDeviceById: (id: string) => Promise;
createDevice: (device: DeviceRequest) => Promise, "status">>;
updateDevice: (id: string, device: DeviceRequest) => Promise, "status">>;
+ getTowerSelect: () => Promise;
}
export interface Device {
@@ -16,6 +17,7 @@ export interface Device {
latitude: string | number;
port_amount: number;
status: DeviceStatus;
+ tower_id: string | null;
created_at: string;
updated_at: string;
}
@@ -29,10 +31,12 @@ export interface DeviceRequest extends Omit Promise;
getAll: () => Promise;
find: (id: string) => Promise;
create: (device: DeviceRequest) => Promise;
@@ -40,7 +44,12 @@ export interface DeviceState extends ErrorState, CacheState {
clearDevice: () => void;
}
-export interface DeviceErrorInputState {
- username?: string | null;
- password?: string | null;
+export interface DeviceDataTable extends Pick {
+ address: string;
+ total_used_port: string | number;
+}
+
+export interface IGetTowerSelect {
+ id: string;
+ tower_code: string;
}
\ No newline at end of file
diff --git a/src/types/fishbone.types.ts b/src/types/fishbone.types.ts
new file mode 100644
index 0000000..b330d98
--- /dev/null
+++ b/src/types/fishbone.types.ts
@@ -0,0 +1,62 @@
+import { ResponseApi } from "./response.types";
+import { CacheState, ErrorState, SelectState } from "./store.types";
+
+export interface FishboneRepositoryProps {
+ getAll: () => Promise;
+ getFishboneById: (id: string) => Promise;
+ createFishbone: (fishbone: FishboneRequest) => Promise, "status">>;
+ updateFishbone: (id: string, fishbone: FishboneRequest) => Promise, "status">>;
+ getBackboneSelect: () => Promise;
+ getDeviceSelect: () => Promise;
+}
+
+export interface Fishbone {
+ id: string;
+ backbone_id: string;
+ backbone_core: string;
+ dev_start_id: string;
+ dev_end_id: string;
+ longitude: string | number;
+ latitude: string | number;
+ core_amount: number;
+ created_at: string;
+}
+
+export interface FishboneRequest extends Omit {}
+
+/**
+ * Fishbone State
+ * =============
+ */
+export interface FishboneState extends ErrorState, CacheState {
+ data?: FishboneDataTable[];
+ fishbone?: Fishbone | null;
+ isLoading: boolean;
+ lastUpdate: number | null;
+ backboneSelect: SelectState[] | null;
+ deviceSelect: SelectState[] | null;
+ getBackboneSelect: () => Promise;
+ getDeviceSelect: () => Promise;
+ getAll: () => Promise;
+ find: (id: string) => Promise;
+ create: (fishbone: FishboneRequest) => Promise;
+ update: (id: string, fishbone: FishboneRequest) => Promise;
+ clearFishbone: () => void;
+}
+
+export interface FishboneDataTable extends Pick {
+ backbone: string;
+ address: string;
+ device_start: string;
+ device_end: string;
+}
+
+export interface IGetBackboneSelect {
+ id: string;
+ backbone_code: string;
+}
+
+export interface IGetDeviceSelect {
+ id: string;
+ device_code: string;
+}
\ No newline at end of file
diff --git a/src/types/store.types.ts b/src/types/store.types.ts
index 561ccfa..4cbad01 100644
--- a/src/types/store.types.ts
+++ b/src/types/store.types.ts
@@ -5,4 +5,9 @@ export interface ErrorState {
export interface CacheState {
cacheExpired: () => boolean;
+}
+
+export interface SelectState {
+ value: string;
+ label: string;
}
\ No newline at end of file