feat: tambah stale villages alert card di halaman overview desa-plus
This commit is contained in:
@@ -32,6 +32,7 @@ export const API_URLS = {
|
||||
if (dateTo) params.set('dateTo', dateTo)
|
||||
return `${DESA_PLUS_PROXY}/api/monitoring/log-all-villages?${params}`
|
||||
},
|
||||
getStaleVillages: (days: 7 | 14 | 30 = 7) => `${DESA_PLUS_PROXY}/api/monitoring/stale-villages?days=${days}`,
|
||||
getGridOverview: () => `${DESA_PLUS_PROXY}/api/monitoring/grid-overview`,
|
||||
getDailyActivity: (range: 7 | 30 | 90 = 7) => `${DESA_PLUS_PROXY}/api/monitoring/daily-activity?range=${range}`,
|
||||
getComparisonActivity: (range: 7 | 30 | 90 = 7) => `${DESA_PLUS_PROXY}/api/monitoring/comparison-activity?range=${range}`,
|
||||
|
||||
@@ -4,10 +4,15 @@ import { SummaryCard } from '@/frontend/components/SummaryCard'
|
||||
import { useSession } from '@/frontend/hooks/useAuth'
|
||||
import {
|
||||
ActionIcon,
|
||||
Anchor,
|
||||
Badge,
|
||||
Button,
|
||||
Collapse,
|
||||
Divider,
|
||||
Group,
|
||||
Modal,
|
||||
Paper,
|
||||
SegmentedControl,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Switch,
|
||||
@@ -25,6 +30,8 @@ import {
|
||||
TbActivity,
|
||||
TbAlertTriangle,
|
||||
TbBuildingCommunity,
|
||||
TbChevronDown,
|
||||
TbChevronUp,
|
||||
TbRefresh,
|
||||
TbVersions,
|
||||
} from 'react-icons/tb'
|
||||
@@ -54,12 +61,15 @@ function AppOverviewPage() {
|
||||
|
||||
const [dailyRange, setDailyRange] = useState<7 | 30 | 90>(7)
|
||||
const [comparisonRange, setComparisonRange] = useState<7 | 30 | 90>(7)
|
||||
const [staleDays, setStaleDays] = useState<7 | 14 | 30>(7)
|
||||
const [staleExpanded, { toggle: toggleStale }] = useDisclosure(false)
|
||||
|
||||
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(dailyRange) : null, fetcher)
|
||||
const { data: comparisonRes, isLoading: comparisonLoading, mutate: mutateComparison } = useSWR(isDesaPlus ? API_URLS.getComparisonActivity(comparisonRange) : null, fetcher)
|
||||
|
||||
const { data: appData, isLoading: appLoading } = useSWR(`/api/apps/${appId}`, fetcher)
|
||||
const { data: staleRes } = useSWR(isDesaPlus ? API_URLS.getStaleVillages(staleDays) : null, fetcher)
|
||||
|
||||
const grid = gridRes?.data
|
||||
const dailyData = dailyRes?.data || []
|
||||
@@ -248,6 +258,62 @@ function AppOverviewPage() {
|
||||
/>
|
||||
</SimpleGrid>
|
||||
|
||||
{isDesaPlus && staleRes?.data?.count > 0 && (
|
||||
<Paper
|
||||
withBorder
|
||||
radius="xl"
|
||||
className="glass"
|
||||
p="md"
|
||||
style={{ borderColor: 'var(--mantine-color-orange-7)' }}
|
||||
>
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Group gap="sm" wrap="nowrap">
|
||||
<TbAlertTriangle size={18} color="var(--mantine-color-orange-5)" style={{ flexShrink: 0 }} />
|
||||
<Text fw={700} size="sm" c="orange.4">
|
||||
{staleRes.data.count} desa tidak ada aktivitas dalam {staleDays} hari terakhir
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap="xs" wrap="nowrap">
|
||||
<SegmentedControl
|
||||
size="xs"
|
||||
value={String(staleDays)}
|
||||
onChange={(v) => setStaleDays(Number(v) as 7 | 14 | 30)}
|
||||
data={[
|
||||
{ label: '7H', value: '7' },
|
||||
{ label: '14H', value: '14' },
|
||||
{ label: '30H', value: '30' },
|
||||
]}
|
||||
/>
|
||||
<ActionIcon variant="subtle" color="gray" size="sm" onClick={toggleStale}>
|
||||
{staleExpanded ? <TbChevronUp size={15} /> : <TbChevronDown size={15} />}
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
<Collapse in={staleExpanded}>
|
||||
<Divider my="sm" opacity={0.2} />
|
||||
<Stack gap={6}>
|
||||
{staleRes.data.villages.map((v: { id: string; name: string; daysSince: number | null }) => (
|
||||
<Group key={v.id} justify="space-between" wrap="nowrap">
|
||||
<Anchor
|
||||
size="sm"
|
||||
fw={500}
|
||||
c="dimmed"
|
||||
onClick={() => navigate({ to: `/apps/${appId}/villages/${v.id}` })}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
{v.name}
|
||||
</Anchor>
|
||||
<Text size="xs" c="orange.6" fw={600}>
|
||||
{v.daysSince === null ? 'Belum pernah ada aktivitas' : `${v.daysSince} hari lalu`}
|
||||
</Text>
|
||||
</Group>
|
||||
))}
|
||||
</Stack>
|
||||
</Collapse>
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
<Group justify="space-between" align="flex-end">
|
||||
<Stack gap={2}>
|
||||
<Title order={4}>Analytics</Title>
|
||||
|
||||
Reference in New Issue
Block a user