diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..a4112fe Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json index 7d357e2..d0c4921 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@mantine/charts": "^9.0.0", "@mantine/core": "^8.3.18", "@mantine/hooks": "^8.3.18", + "@mantine/notifications": "^8.3.18", "@prisma/client": "6", "@tanstack/react-query": "^5.95.2", "@tanstack/react-router": "^1.168.10", diff --git a/src/frontend/App.tsx b/src/frontend/App.tsx index 838a693..453a205 100644 --- a/src/frontend/App.tsx +++ b/src/frontend/App.tsx @@ -1,5 +1,7 @@ import { ColorSchemeScript, MantineProvider, createTheme } from '@mantine/core' import '@mantine/core/styles.css' +import '@mantine/notifications/styles.css' +import { Notifications } from '@mantine/notifications' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { createRouter, RouterProvider } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' @@ -61,6 +63,7 @@ export function App() { <> + diff --git a/src/frontend/config/api.ts b/src/frontend/config/api.ts index 0302546..bfcaf88 100644 --- a/src/frontend/config/api.ts +++ b/src/frontend/config/api.ts @@ -16,4 +16,5 @@ export const API_URLS = { getGridOverview: () => `${API_BASE_URL}/api/monitoring/grid-overview`, getDailyActivity: () => `${API_BASE_URL}/api/monitoring/daily-activity`, getComparisonActivity: () => `${API_BASE_URL}/api/monitoring/comparison-activity`, + postVersionUpdate: () => `${API_BASE_URL}/api/monitoring/version-update`, } diff --git a/src/frontend/routes/apps.$appId.index.tsx b/src/frontend/routes/apps.$appId.index.tsx index 6c737c8..acb394f 100644 --- a/src/frontend/routes/apps.$appId.index.tsx +++ b/src/frontend/routes/apps.$appId.index.tsx @@ -1,3 +1,5 @@ +import { useEffect, useState } from 'react' +import { notifications } from '@mantine/notifications' import { VillageActivityLineChart, VillageComparisonBarChart } from '@/frontend/components/DashboardCharts' import { ErrorDataTable } from '@/frontend/components/ErrorDataTable' import { SummaryCard } from '@/frontend/components/SummaryCard' @@ -40,6 +42,13 @@ function AppOverviewPage() { const isDesaPlus = appId === 'desa-plus' const [versionModalOpened, { open: openVersionModal, close: closeVersionModal }] = useDisclosure(false) + // Form State + const [latestVersion, setLatestVersion] = useState('') + const [minVersion, setMinVersion] = useState('') + const [messageUpdate, setMessageUpdate] = useState('') + const [maintenance, setMaintenance] = useState(false) + const [isSaving, setIsSaving] = useState(false) + // Data Fetching const { data: gridRes, isLoading: gridLoading, mutate: mutateGrid } = useSWR(isDesaPlus ? API_URLS.getGridOverview() : null, fetcher) const { data: dailyRes, isLoading: dailyLoading, mutate: mutateDaily } = useSWR(isDesaPlus ? API_URLS.getDailyActivity() : null, fetcher) @@ -49,31 +58,93 @@ function AppOverviewPage() { const dailyData = dailyRes?.data || [] const comparisonData = comparisonRes?.data || [] + // Initialize form when data loads or modal opens + useEffect(() => { + if (grid?.version && versionModalOpened) { + setLatestVersion(grid.version.mobile_latest_version || '') + setMinVersion(grid.version.mobile_minimum_version || '') + setMessageUpdate(grid.version.mobile_message_update || '') + setMaintenance(grid.version.mobile_maintenance === 'true') + } + }, [grid, versionModalOpened]) + const handleRefresh = () => { mutateGrid() mutateDaily() mutateComparison() } + const handleSaveVersion = async () => { + setIsSaving(true) + try { + const response = await fetch(API_URLS.postVersionUpdate(), { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + mobile_latest_version: latestVersion, + mobile_minimum_version: minVersion, + mobile_maintenance: maintenance, + mobile_message_update: messageUpdate, + }), + }) + + if (response.ok) { + notifications.show({ + title: 'Update Successful', + message: 'Application version information has been updated.', + color: 'teal', + }) + mutateGrid() + closeVersionModal() + } else { + notifications.show({ + title: 'Update Failed', + message: 'Failed to update version information. Please check your data.', + color: 'red', + }) + } + } catch (error) { + notifications.show({ + title: 'Network Error', + message: 'Could not connect to the server. Please try again later.', + color: 'red', + }) + } finally { + setIsSaving(false) + } + } + return ( <> - - + setLatestVersion(e.currentTarget.value)} + /> + setMinVersion(e.currentTarget.value)} + />