import { useQuery } from '@tanstack/react-query'
import { VillageActivityLineChart, VillageComparisonBarChart } from '@/frontend/components/DashboardCharts'
import { ErrorDataTable } from '@/frontend/components/ErrorDataTable'
import { SummaryCard } from '@/frontend/components/SummaryCard'
import { useSession } from '@/frontend/hooks/useAuth'
import {
Badge,
Button,
Group,
Modal,
SimpleGrid,
Stack,
Switch,
Text,
Textarea,
TextInput,
Title
} from '@mantine/core'
import { useDisclosure } from '@mantine/hooks'
import { notifications } from '@mantine/notifications'
import { createFileRoute, useNavigate, useParams } from '@tanstack/react-router'
import { useEffect, useState } from 'react'
import {
TbActivity,
TbAlertTriangle,
TbBuildingCommunity,
TbVersions
} from 'react-icons/tb'
import useSWR from 'swr'
import { API_URLS } from '../config/api'
export const Route = createFileRoute('/apps/$appId/')({
component: AppOverviewPage,
})
const fetcher = (url: string) => fetch(url).then((res) => res.json())
function AppOverviewPage() {
const { appId } = useParams({ from: '/apps/$appId/' })
const navigate = useNavigate()
const isDesaPlus = appId === 'desa-plus'
const [versionModalOpened, { open: openVersionModal, close: closeVersionModal }] = useDisclosure(false)
const { data: session } = useSession()
const isDeveloper = session?.user?.role === 'DEVELOPER'
// 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)
const { data: comparisonRes, isLoading: comparisonLoading, mutate: mutateComparison } = useSWR(isDesaPlus ? API_URLS.getComparisonActivity() : null, fetcher)
const { data: appData, isLoading: appLoading } = useQuery({
queryKey: ['apps', appId],
queryFn: () => fetch(`/api/apps/${appId}`).then((r) => r.json()),
})
const grid = gridRes?.data
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) {
await fetch(API_URLS.createLog(), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'UPDATE', message: `Update version information: ${JSON.stringify({ latestVersion, minVersion, maintenance, messageUpdate })}` })
}).catch(console.error)
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)}
/>
Overview
Detailed metrics for {isDesaPlus ? 'Desa+' : appId}
{/*
*/}
Min. Version
{grid?.version?.mobile_minimum_version || '-'}
Maintenance
{grid?.version?.mobile_maintenance?.toUpperCase() || 'FALSE'}
0 } : undefined}
/>
navigate({ to: `/apps/${appId}/villages` })}
>
Nonactive Villages
{grid?.village?.inactive || 0}
navigate({ to: `/apps/${appId}/errors` })}
/>
>
)
}