diff --git a/src/apis/action.ts b/src/apis/action.ts index 90c89e9..c200ee4 100644 --- a/src/apis/action.ts +++ b/src/apis/action.ts @@ -1,10 +1,6 @@ -import network from "@/utils/network"; -import { - Action, - ActionHistory, - DispatchActionRequest, - LastActionResponse -} from './action.types' +import network from '@/utils/network'; + +import { Action, ActionHistory, DispatchActionRequest, LastActionResponse } from './action.types'; const dispatchAction = (request: DispatchActionRequest) => network.post("/action/dispatch", JSON.stringify(request)) const getActions = (device_id: number): Promise => network.get(`/action/available?device_id=${device_id}`) diff --git a/src/apis/action.types.ts b/src/apis/action.types.ts index 188b2e7..5bc252d 100644 --- a/src/apis/action.types.ts +++ b/src/apis/action.types.ts @@ -1,4 +1,4 @@ -import { ActionIcon, ActionSource, ActionType, ActionValue } from "@/constants/action" +import { ActionIcon, ActionSource, ActionType, ActionValue } from '@/constants/action'; export type Action = { id: number, diff --git a/src/apis/report.ts b/src/apis/report.ts index 5642866..9704941 100644 --- a/src/apis/report.ts +++ b/src/apis/report.ts @@ -1,5 +1,6 @@ -import network from "@/utils/network"; -import { GetSensorReportRequest, SensorReport } from "./report.types"; +import network from '@/utils/network'; + +import { GetSensorReportRequest, SensorReport } from './report.types'; const getSensorReport = (request: GetSensorReportRequest): Promise => network.post(`/chart`, JSON.stringify(request)) diff --git a/src/apis/report.types.ts b/src/apis/report.types.ts index c712db2..1eb86c0 100644 --- a/src/apis/report.types.ts +++ b/src/apis/report.types.ts @@ -1,4 +1,4 @@ -import { SensorType } from "@/constants/sensor" +import { SensorType } from '@/constants/sensor'; export type GetSensorReportRequest = { start_time: string diff --git a/src/apis/scheduler.ts b/src/apis/scheduler.ts index 457a3ef..341dde7 100644 --- a/src/apis/scheduler.ts +++ b/src/apis/scheduler.ts @@ -1,5 +1,6 @@ -import network from "@/utils/network"; -import { CreateSchedulerRequest, ScheduledTask } from "./scheduler.types"; +import network from '@/utils/network'; + +import { CreateSchedulerRequest, ScheduledTask } from './scheduler.types'; const createSchedule = (request: CreateSchedulerRequest) => network.post("/schedule", JSON.stringify(request)) const deleteSchedule = (id: number) => network.delete(`/schedule?id=${id}`) diff --git a/src/apis/scheduler.types.ts b/src/apis/scheduler.types.ts index b4b72df..6b39728 100644 --- a/src/apis/scheduler.types.ts +++ b/src/apis/scheduler.types.ts @@ -1,6 +1,7 @@ -import { SchedulerRecurringMode } from "@/constants/scheduler" -import { DispatchActionRequest } from "./action.types" -import { ScheduleStatus } from "@/constants/action" +import { ScheduleStatus } from '@/constants/action'; +import { SchedulerRecurringMode } from '@/constants/scheduler'; + +import { DispatchActionRequest } from './action.types'; export type CreateSchedulerRequest = { name: string diff --git a/src/apis/setting.ts b/src/apis/setting.ts index d1e98a1..a80e1b3 100644 --- a/src/apis/setting.ts +++ b/src/apis/setting.ts @@ -1,5 +1,6 @@ -import network from "@/utils/network"; -import { Actuator } from "./setting.types"; +import network from '@/utils/network'; + +import { Actuator } from './setting.types'; const getActuators = (device_id: number): Promise => network.get(`/actuators?device_id=${device_id}`) const updateActuator = (actuator: Actuator) => network.patch('/actuator', JSON.stringify(actuator)) diff --git a/src/apis/setting.types.ts b/src/apis/setting.types.ts index 7340e46..48fec84 100644 --- a/src/apis/setting.types.ts +++ b/src/apis/setting.types.ts @@ -1,4 +1,4 @@ -import { ActionIcon, ActionType } from "@/constants/action" +import { ActionIcon, ActionType } from '@/constants/action'; export type Actuator = { id: number, diff --git a/src/apis/user.ts b/src/apis/user.ts index 13dbd41..fb05780 100644 --- a/src/apis/user.ts +++ b/src/apis/user.ts @@ -1,6 +1,7 @@ -import network from "@/utils/network"; -import { AuthRequest, AuthResponse } from "./user.types"; -import { UserInfo } from "@/stores/auh.types"; +import { UserInfo } from '@/stores/auh.types'; +import network from '@/utils/network'; + +import { AuthRequest, AuthResponse } from './user.types'; const getUserInfo = async (): Promise => network.get('/users/info') const getUserList = async (): Promise => network.get('/users') diff --git a/src/components/confirmation-dialog/index.tsx b/src/components/confirmation-dialog/index.tsx index 9f38642..deef1e5 100644 --- a/src/components/confirmation-dialog/index.tsx +++ b/src/components/confirmation-dialog/index.tsx @@ -1,5 +1,8 @@ -import { Button, DialogContent, DialogTitle, Modal as JoyModal, ModalDialog, Typography } from "@mui/joy"; -import { Transition, TransitionStatus } from "react-transition-group"; +import { Transition, TransitionStatus } from 'react-transition-group'; + +import { + Button, DialogContent, DialogTitle, Modal as JoyModal, ModalDialog, Typography +} from '@mui/joy'; type ModalTransition = { [key in TransitionStatus]: React.CSSProperties; diff --git a/src/components/loading/index.tsx b/src/components/loading/index.tsx new file mode 100644 index 0000000..a627565 --- /dev/null +++ b/src/components/loading/index.tsx @@ -0,0 +1,16 @@ +import { LinearProgress } from '@mui/joy'; + +const Loading = ({ loading, children }: LoadingProps) => { + if (loading) { + return + } + + return <>{children} +} + +type LoadingProps = { + loading: boolean, + children: any +} + +export default Loading \ No newline at end of file diff --git a/src/components/modal/index.tsx b/src/components/modal/index.tsx index 50e0309..5c26da8 100644 --- a/src/components/modal/index.tsx +++ b/src/components/modal/index.tsx @@ -1,7 +1,9 @@ -import { Button, ColorPaletteProp, DialogContent, DialogTitle, Modal as JoyModal, ModalDialog, VariantProp } from "@mui/joy"; -import { Box } from "@mui/system"; -import { Transition, TransitionStatus } from "react-transition-group"; +import { Transition, TransitionStatus } from 'react-transition-group'; +import { + Button, ColorPaletteProp, DialogContent, DialogTitle, Modal as JoyModal, ModalDialog, + VariantProp, Box +} from '@mui/joy'; type ModalTransition = { [key in TransitionStatus]: React.CSSProperties; diff --git a/src/constants/action.ts b/src/constants/action.ts index ca32776..d374607 100644 --- a/src/constants/action.ts +++ b/src/constants/action.ts @@ -1,8 +1,8 @@ +import BoltIcon from '@mui/icons-material/Bolt'; import FluorescentIcon from '@mui/icons-material/Fluorescent'; +import ForestIcon from '@mui/icons-material/Forest'; import WaterDropIcon from '@mui/icons-material/WaterDrop'; import WbIncandescentIcon from '@mui/icons-material/WbIncandescent'; -import BoltIcon from '@mui/icons-material/Bolt'; -import ForestIcon from '@mui/icons-material/Forest'; export enum ActionSource { User = 1, diff --git a/src/main.tsx b/src/main.tsx index 6e09733..089a5fa 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,23 +1,24 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import { initializeApp } from "firebase/app"; -import { getAnalytics } from "firebase/analytics"; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools' -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs' -import dayjs from 'dayjs'; -import timezone from 'dayjs/plugin/timezone'; -import utc from 'dayjs/plugin/utc'; -import App from './pages/App.tsx' -import 'dayjs/locale/id' - +import 'dayjs/locale/id'; import '@fontsource/inter/400.css'; import '@fontsource/inter/500.css'; import '@fontsource/inter/600.css'; import '@fontsource/inter/700.css'; +import './index.css'; + +import dayjs from 'dayjs'; +import timezone from 'dayjs/plugin/timezone'; +import utc from 'dayjs/plugin/utc'; +import { getAnalytics } from 'firebase/analytics'; +import { initializeApp } from 'firebase/app'; +import React from 'react'; +import ReactDOM from 'react-dom/client'; -import './index.css' import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; + +import App from '@/pages/App.tsx'; const firebaseConfig = { apiKey: "AIzaSyDybZITMkE7sCujRU-MlJlSmwmg9agdBbA", diff --git a/src/pages/App.tsx b/src/pages/App.tsx index adf040b..fb1a6ae 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -1,10 +1,12 @@ -import { Box, Button, LinearProgress, Snackbar, Typography } from '@mui/joy'; import './App.css'; -import { Outlet, RouterProvider, createRootRoute, createRoute, createRouter, redirect } from '@tanstack/react-router'; import useAuthStore from '@/stores/auth'; import useNotification from '@/stores/notification'; +import { Box, Button, LinearProgress, Snackbar, Typography } from '@mui/joy'; import { useQueryClient } from '@tanstack/react-query'; +import { + createRootRoute, createRoute, createRouter, Outlet, redirect, RouterProvider +} from '@tanstack/react-router'; const Root = () => { const notification = useNotification() diff --git a/src/pages/auth/index.tsx b/src/pages/auth/index.tsx index cdd8d21..ccbbe39 100644 --- a/src/pages/auth/index.tsx +++ b/src/pages/auth/index.tsx @@ -1,14 +1,14 @@ -import { Button, CircularProgress, Link, Typography } from "@mui/joy" -import { Grid, TextField } from "@mui/material" -import { createLazyRoute, useNavigate } from "@tanstack/react-router" +import { useEffect, useState } from 'react'; -import icon from '@/assets/icon.png' -import { useEffect, useState } from "react" -import userAPI from '@/apis/user' -import { useMutation, useQuery } from "@tanstack/react-query" -import { AuthRequest } from "@/apis/user.types" -import useAuthStore from "@/stores/auth" -import useNotification from "@/stores/notification" +import userAPI from '@/apis/user'; +import { AuthRequest } from '@/apis/user.types'; +import icon from '@/assets/icon.png'; +import useAuthStore from '@/stores/auth'; +import useNotification from '@/stores/notification'; +import { Button, CircularProgress, Link, Typography } from '@mui/joy'; +import { Grid, TextField } from '@mui/material'; +import { useMutation, useQuery } from '@tanstack/react-query'; +import { createLazyRoute, useNavigate } from '@tanstack/react-router'; const Auth = () => { const [isLoginState, setIsLoginState] = useState(true) diff --git a/src/pages/home/admin/index.tsx b/src/pages/home/admin/index.tsx index 2ebf2fa..334f1a9 100644 --- a/src/pages/home/admin/index.tsx +++ b/src/pages/home/admin/index.tsx @@ -1,15 +1,16 @@ -import Modal from "@/components/modal" -import { Card, Chip, Grid, Option, Select, Typography } from "@mui/joy" -import { Box, TextField } from "@mui/material" -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" -import { createLazyRoute } from "@tanstack/react-router" - -import settingAPI from '@/apis/setting' -import userAPI from '@/apis/user' -import { useState } from "react" -import { Actuator } from "@/apis/setting.types" -import { UserInfo } from "@/stores/auh.types" -import useNotification from "@/stores/notification" +import { useState } from 'react'; + +import settingAPI from '@/apis/setting'; +import { Actuator } from '@/apis/setting.types'; +import userAPI from '@/apis/user'; +import Loading from '@/components/loading'; +import Modal from '@/components/modal'; +import { UserInfo } from '@/stores/auh.types'; +import useNotification from '@/stores/notification'; +import { Card, Chip, Grid, Option, Select, Typography } from '@mui/joy'; +import { Box, TextField } from '@mui/material'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { createLazyRoute } from '@tanstack/react-router'; type itemState = Actuator | UserInfo | null @@ -44,9 +45,9 @@ const renderModalBody = (item: itemState, mutator: (item: itemState) => void): J return ( mutator({ ...item, name: e.target.value })} /> - - mutator({ ...item, pin_number: Number(e.target.value) })} /> - mutator({ ...item, terminal_number: Number(e.target.value) })} /> + + mutator({ ...item, pin_number: Number(e.target.value) })} /> + mutator({ ...item, terminal_number: Number(e.target.value) })} /> ) @@ -109,33 +110,37 @@ const Admin = () => { Admin Panel Users - - {usersQuery.data?.map(user => ( - handleCardClick(user)}> - - - {user.name} - {user.role == 99 && Admin} + + + {usersQuery.data?.map(user => ( + handleCardClick(user)}> + + + {user.name} + {user.role == 99 && Admin} + + {user.is_active ? "Active" : "Not Active"} - {user.is_active ? "Active" : "Not Active"} - - - ))} - + + ))} + + Panels - - {actuatorsQuery.data?.map(actuator => ( - handleCardClick(actuator)}> - - {actuator.name} - - Pin: {actuator.pin_number} - {actuator.terminal_number} - - - - ))} - + + + {actuatorsQuery.data?.map(actuator => ( + handleCardClick(actuator)}> + + {actuator.name} + + Pin: {actuator.pin_number} + {actuator.terminal_number} + + + + ))} + + { const [mutationLoading, setMutationLoading] = useState<{ [key: string]: boolean }>({}) const [reportStartTime, setReportStartTime] = useState(createDateHourDayJSNow().add(-1, "hour")) const sensorReportCardRef = useRef() - const { setTab } = useTabStore() + const navigate = useNavigate() const userInfoQuery = useQuery({ queryFn: userAPI.getUserInfo, @@ -133,11 +129,7 @@ const Dashboard = () => { Kelembapan Tanah - {soilMoistureSensorReportQuery.isLoading ? ( - - - - ) : ( + { }} width={sensorReportCardRef?.current?.clientWidth || 0} /> - )} + Panel Kontrol - {actions.isLoading ? : - (actions.data?.length || 0) == 0 ? ( - - Panel aktif tidak ditemukan. Pastikan panel di halaman setTab(3)} fontWeight='600'>pengaturan telah aktif - - ) : - - {actions.data?.map((action, index) => { - const state = actionStates[index] - return mutateState(action.id, !state.data?.value)} /> - })} - - } + + { + (actions.data?.length || 0) == 0 ? ( + + Panel aktif tidak ditemukan. Pastikan panel di halaman navigate({ to: '/setting' })} fontWeight='600'>pengaturan telah aktif + + ) : + + {actions.data?.map((action, index) => { + const state = actionStates[index] + return mutateState(action.id, !state.data?.value)} /> + })} + + } + Riwayat Kontrol - {actionHistoriesQuery.isLoading ? : ( + {actionHistoriesQuery.data?.map(history => { const Icon = getActionIcon(history.action.icon) @@ -226,7 +220,7 @@ const Dashboard = () => { ) })} - )} + } @@ -255,10 +249,7 @@ const appendReportData = (prev: SensorReport, report?: SensorReport): SensorRepo data: [...prev.data.slice(report.data.length), ...report.data] } } -const createDateHourDayJSNow = () => { - return dayjs() - .set("second", 0) -} +const createDateHourDayJSNow = () => dayjs().set("second", 0) const generateGreetingMessage = () => { const date = new Date() diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx index 7bc6a9b..9fa6acf 100644 --- a/src/pages/home/index.tsx +++ b/src/pages/home/index.tsx @@ -1,15 +1,16 @@ -import ListItemDecorator from '@mui/joy/ListItemDecorator'; -import Tabs from '@mui/joy/Tabs'; -import TabList from '@mui/joy/TabList'; -import Tab, { tabClasses } from '@mui/joy/Tab'; +import userAPI from '@/apis/user'; +import { UserInfo } from '@/stores/auh.types'; +import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings'; import HomeRoundedIcon from '@mui/icons-material/HomeRounded'; import ScheduleIcon from '@mui/icons-material/Schedule'; import SettingIcon from '@mui/icons-material/Settings'; -import { Outlet, createLazyRoute, useNavigate, useRouterState } from '@tanstack/react-router'; -import { Grid } from '@mui/joy'; +import { Grid, Typography } from '@mui/joy'; +import ListItemDecorator from '@mui/joy/ListItemDecorator'; +import Tab, { tabClasses } from '@mui/joy/Tab'; +import TabList from '@mui/joy/TabList'; +import Tabs from '@mui/joy/Tabs'; import { useQuery } from '@tanstack/react-query'; -import userAPI from '@/apis/user' -import { UserInfo } from '@/stores/auh.types'; +import { createLazyRoute, Outlet, useNavigate, useRouterState } from '@tanstack/react-router'; const colors = ['primary', 'danger', 'success', 'warning'] as const; const tabs = [ @@ -89,7 +90,7 @@ const BottomNavigation = () => { - Dashboard + Dashboard { - Penjadwalan + Penjadwalan { - Pengaturan + Pengaturan {userInfo.data?.role == 99 && ( { {...(currentIndex === 3 && { color: colors[3] })} > - + - Admin + Admin )} diff --git a/src/pages/home/schedule/index.tsx b/src/pages/home/schedule/index.tsx index a8437d5..1c00f14 100644 --- a/src/pages/home/schedule/index.tsx +++ b/src/pages/home/schedule/index.tsx @@ -1,29 +1,32 @@ -import { DispatchActionRequest } from "@/apis/action.types"; +import dayjs, { Dayjs } from 'dayjs'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { DispatchActionRequest } from '@/apis/action.types'; import schedulerAPI from '@/apis/scheduler'; -import { CreateSchedulerRequest, ScheduledTask } from "@/apis/scheduler.types"; -import { ActionType, ActionTypeValues, ScheduleStatusNames } from "@/constants/action"; -import { SchedulerRecurringMode } from "@/constants/scheduler"; -import { styled } from '@mui/material/styles'; +import { CreateSchedulerRequest, ScheduledTask } from '@/apis/scheduler.types'; +import settingAPI from '@/apis/setting'; +import ConfirmationDialog from '@/components/confirmation-dialog'; +import Loading from '@/components/loading'; +import Modal from '@/components/modal'; +import { ActionType, ActionTypeValues, ScheduleStatusNames } from '@/constants/action'; +import { defaultDateTimeFormat } from '@/constants/date'; +import { SchedulerRecurringMode } from '@/constants/scheduler'; +import useNotification from '@/stores/notification'; import Add from '@mui/icons-material/Add'; import DeleteIcon from '@mui/icons-material/Delete'; -import { Box, Button, Card, CardContent, Grid, LinearProgress, Link, Option, Select, Tab, TabList, Tabs, Typography, tabClasses } from "@mui/joy"; -import { TimePicker } from "@mui/x-date-pickers"; -import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; -import { renderTimeViewClock } from '@mui/x-date-pickers/timeViewRenderers'; -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import dayjs, { Dayjs } from "dayjs"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import Modal from '@/components/modal'; -import { Collapse, TextField } from "@mui/material"; +import { + Box, Button, Card, CardContent, Grid, Link, Option, Select, Tab, tabClasses, TabList, Tabs, + Typography +} from '@mui/joy'; import IconButton, { IconButtonProps } from '@mui/joy/IconButton'; -import { defaultDateTimeFormat } from "@/constants/date"; -import ConfirmationDialog from "@/components/confirmation-dialog" - -import settingAPI from "@/apis/setting" -import useTabStore from "@/stores/tab"; -import { createLazyRoute } from "@tanstack/react-router"; -import useNotification from "@/stores/notification"; +import { Collapse, TextField } from '@mui/material'; +import { styled } from '@mui/material/styles'; +import { TimePicker } from '@mui/x-date-pickers'; +import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker'; +import { renderTimeViewClock } from '@mui/x-date-pickers/timeViewRenderers'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { createLazyRoute, useNavigate } from '@tanstack/react-router'; const scheduleModeTabMap: { [key: number]: SchedulerRecurringMode } = { 0: SchedulerRecurringMode.NONE, @@ -74,9 +77,7 @@ const Schedule = () => { onSuccess: () => { queryClient.invalidateQueries({ queryKey: [schedulerAPI.QUERY_KEY_GET_UPCOMING_SCHEDULES, 1] }) setIsAddModalOpen(false) - setExpandedSchedule({ - id: -1, - }) + setExpandedSchedule(null) notification.fire("Berhasil mengubah jadwal") }, }) @@ -89,11 +90,9 @@ const Schedule = () => { const [scheduleModeIndex, setScheduleModeIndex] = useState(0) const [scheduleTime, setScheduleTime] = useState(generateDefaultDateTime()) const [actions, setActions] = useState([]) - const [expandedSchedule, setExpandedSchedule] = useState>({ - id: -1, - }) - const setTab = useTabStore(store => store.setTab) + const [expandedSchedule, setExpandedSchedule] = useState(null) const notification = useNotification() + const navigate = useNavigate() const upcomingSchedules = useMemo(() => upcomingSchedulesQuery.data, [upcomingSchedulesQuery.data]) const actuators = useMemo(() => [...actuatorsQuery.data || []], [actuatorsQuery.data]) @@ -117,7 +116,7 @@ const Schedule = () => { setScheduleModeIndex(0) setScheduleTime(generateDefaultDateTime()) setActions([]) - setExpandedSchedule({ id: -1 }) + setExpandedSchedule(null) setIsAddModalOpen(true) } @@ -135,16 +134,16 @@ const Schedule = () => { }, [scheduleName, scheduleDescription, scheduleModeIndex, scheduleTime, actions, duration, addScheduleMutation]) const handleExpandSchedule = (schedule: ScheduledTask) => { - setExpandedSchedule(currentSchedule => schedule.id == currentSchedule.id ? { id: -1 } : schedule) + setExpandedSchedule(currentSchedule => schedule.id == currentSchedule?.id ? null : schedule) } const handleDeleteSchedule = () => { - if (!expandedSchedule.id) return + if (!expandedSchedule) return deleteScheduleMutation.mutate(expandedSchedule.id as number) } const handleEditSchedule = () => { - if (!expandedSchedule.id) return + if (!expandedSchedule) return updateScheduleMutation.mutate({ ...expandedSchedule as ScheduledTask, name: scheduleName, @@ -157,6 +156,7 @@ const Schedule = () => { } const handleEditScheduleAction = () => { + if (!expandedSchedule) return setScheduleName(expandedSchedule.name || "") setScheduleDescription(expandedSchedule.description || "") setScheduleDuration(expandedSchedule.duration || 0) @@ -183,7 +183,7 @@ const Schedule = () => { // Reset schedule time when mode changes useEffect(() => { - if ((expandedSchedule.id || 0) > 0) return + if (!expandedSchedule || expandedSchedule.id > 0) return setScheduleTime(generateDefaultDateTime()) }, [scheduleModeIndex, expandedSchedule]) @@ -199,51 +199,52 @@ const Schedule = () => { startDecorator={} onClick={handleAddNewSchedule} >Tambah Jadwal - {upcomingSchedulesQuery.isLoading && } - {!upcomingSchedulesQuery.isLoading && !upcomingSchedules?.length && Tidak ada Jadwal} - {upcomingSchedules?.map((schedule) => ( - - - - {schedule.name} - {dayjs(schedule.next_run_at).format(defaultDateTimeFormat)} - - handleExpandSchedule(schedule)}> - - - - - - {schedule.description && - Deskripsi - {schedule.description} - } - {schedule.last_run_at && ( + + {!upcomingSchedulesQuery.isLoading && !upcomingSchedules?.length && Tidak ada Jadwal} + {upcomingSchedules?.map((schedule) => ( + + + + {schedule.name} + {dayjs(schedule.next_run_at).format(defaultDateTimeFormat)} + + handleExpandSchedule(schedule)}> + + + + + + {schedule.description && + Deskripsi + {schedule.description} + } + {schedule.last_run_at && ( + + Waktu Eksekusi Terakhir + {dayjs(schedule.last_run_at).format(defaultDateTimeFormat)} + + )} - Waktu Eksekusi Terakhir - {dayjs(schedule.last_run_at).format(defaultDateTimeFormat)} + Status Terakhir + {ScheduleStatusNames[schedule.last_run_status]} - )} - - Status Terakhir - {ScheduleStatusNames[schedule.last_run_status]} - - - - - - - - - ))} + + + + + + + + ))} + {/* Add / Update Schedule Dialog */} 0 ? "Ubah Jadwal" : "Tambah Jadwal"} + title={expandedSchedule ? "Ubah Jadwal" : "Tambah Jadwal"} isOpen={isAddModalOpen} onClose={() => setIsAddModalOpen(false)} buttonActions={[ @@ -252,7 +253,7 @@ const Schedule = () => { variant: 'solid', color: 'primary', loading: addScheduleMutation.isPending || updateScheduleMutation.isPending, - onClick: (expandedSchedule.id || 0) > 0 ? handleEditSchedule : handleSaveSchedule, + onClick: expandedSchedule ? handleEditSchedule : handleSaveSchedule, }, { label: 'Tutup', @@ -263,10 +264,7 @@ const Schedule = () => { ]} > -
+ setScheduleName(e.target.value)} /> setScheduleDescription(e.target.value)} /> setScheduleModeIndex(val as number)} > @@ -323,7 +321,7 @@ const Schedule = () => { defaultAddActionRequest.actuator_id && : ( - Tidak bisa menambah aksi karena tidak ada panel yang aktif. Pastikan panel pada setTab(3)} fontWeight='600'>pengaturan telah aktif + Tidak bisa menambah aksi karena tidak ada panel yang aktif. Pastikan panel pada navigate({ to: '/setting' })} fontWeight='600'>pengaturan telah aktif )} @@ -332,13 +330,13 @@ const Schedule = () => { {/* Confirmation Dialog */} setIsDeleteConfirmationOpen(false)} onOk={handleDeleteSchedule} - title={`Hapus jadwal ${expandedSchedule.name}`} + title={`Hapus jadwal ${expandedSchedule?.name}`} /> ) diff --git a/src/pages/home/setting/index.tsx b/src/pages/home/setting/index.tsx index 315908e..8eb41fa 100644 --- a/src/pages/home/setting/index.tsx +++ b/src/pages/home/setting/index.tsx @@ -1,16 +1,19 @@ -import { Box, Card, Chip, Grid, LinearProgress, Select, Option, Typography, Button } from "@mui/joy" -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" -import settingAPI from '@/apis/setting' -import userAPI from '@/apis/user' -import { ActionIcon, getActionIcon } from "@/constants/action" -import Modal from "@/components/modal" -import { TextField } from "@mui/material" -import { useState } from "react" -import { Actuator } from "@/apis/setting.types" -import { createLazyRoute, useNavigate } from "@tanstack/react-router" -import ConfirmationDialog from "@/components/confirmation-dialog" -import useAuthStore from "@/stores/auth" -import useNotification from "@/stores/notification" +import { useState } from 'react'; + +import settingAPI from '@/apis/setting'; +import { Actuator } from '@/apis/setting.types'; +import userAPI from '@/apis/user'; +import ConfirmationDialog from '@/components/confirmation-dialog'; +import Modal from '@/components/modal'; +import { ActionIcon, getActionIcon } from '@/constants/action'; +import useAuthStore from '@/stores/auth'; +import useNotification from '@/stores/notification'; +import { + Box, Button, Card, Chip, Grid, LinearProgress, Option, Select, Typography +} from '@mui/joy'; +import { TextField } from '@mui/material'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { createLazyRoute, useNavigate } from '@tanstack/react-router'; const Setting = () => { const [selectedPanel, setSelectedPanel] = useState() diff --git a/src/stores/auth.ts b/src/stores/auth.ts index d1b7cbc..1b08e0d 100644 --- a/src/stores/auth.ts +++ b/src/stores/auth.ts @@ -1,6 +1,7 @@ -import { create } from "zustand"; -import { AuthStore } from "./auh.types"; -import { createJSONStorage, persist } from "zustand/middleware"; +import { create } from 'zustand'; +import { createJSONStorage, persist } from 'zustand/middleware'; + +import { AuthStore } from './auh.types'; const useAuthStore = create()( persist( diff --git a/src/stores/notification.ts b/src/stores/notification.ts index 7ac2c51..bd35936 100644 --- a/src/stores/notification.ts +++ b/src/stores/notification.ts @@ -1,5 +1,6 @@ -import { create } from "zustand" -import { NotificationStore, NotificationType } from "./notification.types" +import { create } from 'zustand'; + +import { NotificationStore, NotificationType } from './notification.types'; const useNotification = create()( (set) => ({ diff --git a/src/stores/tab.ts b/src/stores/tab.ts deleted file mode 100644 index 059e02c..0000000 --- a/src/stores/tab.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { create } from "zustand"; -import { TabState } from "./tab.types"; - -const useTabStore = create()( - (set) => ({ - tab: 1, - setTab: (tab: number) => set({ tab }) - }) -) - -export default useTabStore \ No newline at end of file diff --git a/src/stores/tab.types.ts b/src/stores/tab.types.ts deleted file mode 100644 index 4d3f879..0000000 --- a/src/stores/tab.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface TabState { - tab: number, - setTab: (tab: number) => void -} \ No newline at end of file diff --git a/src/utils/network.ts b/src/utils/network.ts index dfb695c..eb2cb07 100644 --- a/src/utils/network.ts +++ b/src/utils/network.ts @@ -1,4 +1,4 @@ -import useAuthStore from "@/stores/auth" +import useAuthStore from '@/stores/auth'; const BASE_URL = import.meta.env.VITE_BASE_URL