upd: role akses
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import { BarChart, LineChart } from '@mantine/charts'
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Group,
|
||||
Paper,
|
||||
Stack,
|
||||
Text,
|
||||
Group,
|
||||
ThemeIcon,
|
||||
Box,
|
||||
Badge,
|
||||
useMantineTheme
|
||||
} from '@mantine/core'
|
||||
import { LineChart, BarChart } from '@mantine/charts'
|
||||
import { TbTimeline, TbChartBar, TbArrowUpRight } from 'react-icons/tb'
|
||||
import { TbArrowUpRight, TbChartBar, TbTimeline } from 'react-icons/tb'
|
||||
|
||||
interface ChartProps {
|
||||
data?: any[]
|
||||
@@ -32,9 +32,14 @@ export function VillageActivityLineChart({ data = [], isLoading }: ChartProps) {
|
||||
<Text size="xs" c="dimmed">Trend over the last 7 days</Text>
|
||||
</Box>
|
||||
</Group>
|
||||
{
|
||||
isLoading && (
|
||||
<Badge variant="light" color="blue" size="sm" rightSection={<TbArrowUpRight size={12} />}>
|
||||
{isLoading ? '...' : 'Live'}
|
||||
...
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
|
||||
</Group>
|
||||
|
||||
<Box h={300} mt="lg">
|
||||
|
||||
@@ -2,6 +2,7 @@ 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,
|
||||
@@ -39,6 +40,8 @@ function AppOverviewPage() {
|
||||
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('')
|
||||
@@ -177,7 +180,7 @@ function AppOverviewPage() {
|
||||
value={gridLoading ? '...' : (grid?.version?.mobile_latest_version || 'N/A')}
|
||||
icon={TbVersions}
|
||||
color="brand-blue"
|
||||
onClick={openVersionModal}
|
||||
onClick={isDeveloper ? openVersionModal : undefined}
|
||||
>
|
||||
<Group justify="space-between" mt="md">
|
||||
<Stack gap={0}>
|
||||
@@ -220,6 +223,7 @@ function AppOverviewPage() {
|
||||
icon={TbAlertTriangle}
|
||||
color="red"
|
||||
isError={true}
|
||||
onClick={() => navigate({ to: `/apps/${appId}/errors` })}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
} from 'react-icons/tb'
|
||||
import useSWR from 'swr'
|
||||
import { API_URLS } from '../config/api'
|
||||
import { useSession } from '../hooks/useAuth'
|
||||
|
||||
const fetcher = (url: string) => fetch(url).then((res) => res.json())
|
||||
|
||||
@@ -149,6 +150,9 @@ function VillageDetailPage() {
|
||||
const { appId, villageId } = useParams({ from: '/apps/$appId/villages/$villageId' })
|
||||
const navigate = useNavigate()
|
||||
|
||||
const { data: session } = useSession()
|
||||
const isDeveloper = session?.user?.role === 'DEVELOPER'
|
||||
|
||||
const { data: infoRes, isLoading: infoLoading, mutate } = useSWR(API_URLS.infoVillages(villageId), fetcher)
|
||||
const { data: gridRes, isLoading: gridLoading } = useSWR(API_URLS.gridVillages(villageId), fetcher)
|
||||
|
||||
@@ -323,6 +327,7 @@ function VillageDetailPage() {
|
||||
onClick={openConfirmModal}
|
||||
radius="md"
|
||||
loading={isUpdating}
|
||||
disabled={!isDeveloper}
|
||||
>
|
||||
{village.isActive ? 'Deactivate' : 'Active'}
|
||||
</Button>
|
||||
|
||||
@@ -1,48 +1,47 @@
|
||||
import { DashboardLayout } from '@/frontend/components/DashboardLayout'
|
||||
import { StatsCard } from '@/frontend/components/StatsCard'
|
||||
import {
|
||||
ActionIcon,
|
||||
Avatar,
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
Container,
|
||||
Divider,
|
||||
Group,
|
||||
List,
|
||||
Modal,
|
||||
Pagination,
|
||||
Paper,
|
||||
PasswordInput,
|
||||
Select,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Table,
|
||||
Tabs,
|
||||
Text,
|
||||
TextInput,
|
||||
Title,
|
||||
Paper,
|
||||
Tabs,
|
||||
Avatar,
|
||||
SimpleGrid,
|
||||
ThemeIcon,
|
||||
List,
|
||||
Divider,
|
||||
Pagination,
|
||||
Modal,
|
||||
Select,
|
||||
PasswordInput,
|
||||
Title,
|
||||
} from '@mantine/core'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useDisclosure } from '@mantine/hooks'
|
||||
import { notifications } from '@mantine/notifications'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
TbPlus,
|
||||
TbSearch,
|
||||
TbPencil,
|
||||
TbTrash,
|
||||
TbUserCheck,
|
||||
TbShieldCheck,
|
||||
TbAccessPoint,
|
||||
TbCircleCheck,
|
||||
TbCircleX,
|
||||
TbClock,
|
||||
TbApps,
|
||||
TbPencil,
|
||||
TbPlus,
|
||||
TbSearch,
|
||||
TbShieldCheck,
|
||||
TbTrash,
|
||||
TbUserCheck
|
||||
} from 'react-icons/tb'
|
||||
import { DashboardLayout } from '@/frontend/components/DashboardLayout'
|
||||
import { StatsCard } from '@/frontend/components/StatsCard'
|
||||
import useSWR from 'swr'
|
||||
import { API_URLS } from '../config/api'
|
||||
import { useSession } from '../hooks/useAuth'
|
||||
|
||||
export const Route = createFileRoute('/users')({
|
||||
component: UsersPage,
|
||||
@@ -75,6 +74,8 @@ function UsersPage() {
|
||||
const [search, setSearch] = useState('')
|
||||
const [debouncedSearch, setDebouncedSearch] = useState('')
|
||||
const [page, setPage] = useState(1)
|
||||
const { data: session } = useSession()
|
||||
const isDeveloper = session?.user?.role === 'DEVELOPER'
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => setDebouncedSearch(search), 300)
|
||||
@@ -244,6 +245,7 @@ function UsersPage() {
|
||||
setPage(1)
|
||||
}}
|
||||
/>
|
||||
{isDeveloper && (
|
||||
<Button
|
||||
variant="gradient"
|
||||
gradient={{ from: '#2563EB', to: '#7C3AED', deg: 135 }}
|
||||
@@ -253,6 +255,7 @@ function UsersPage() {
|
||||
>
|
||||
Add New User
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
|
||||
<Paper withBorder radius="2xl" className="glass" p={0} style={{ overflow: 'hidden' }}>
|
||||
@@ -302,10 +305,10 @@ function UsersPage() {
|
||||
</Table.Td>
|
||||
<Table.Td>
|
||||
<Group gap="xs">
|
||||
<ActionIcon variant="light" size="sm" color="blue" onClick={() => handleOpenEdit(user)}>
|
||||
<ActionIcon disabled={!isDeveloper} variant="light" size="sm" color="blue" onClick={() => handleOpenEdit(user)}>
|
||||
<TbPencil size={14} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant="light" size="sm" color="red" onClick={() => handleOpenDelete(user)}>
|
||||
<ActionIcon disabled={!isDeveloper} variant="light" size="sm" color="red" onClick={() => handleOpenDelete(user)}>
|
||||
<TbTrash size={14} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
|
||||
Reference in New Issue
Block a user