upd: auth

Deskripsi:
-update login
- update struktur database

No Issues
This commit is contained in:
2026-04-15 11:17:04 +08:00
parent 840a89ea0a
commit c66ce4a39b
14 changed files with 273 additions and 173 deletions

View File

@@ -1,5 +1,7 @@
import { useQuery } from '@tanstack/react-query'
import { Container, Stack, Title, Text, SimpleGrid, Group, Button, TextInput, Loader } from '@mantine/core'
import { useDebouncedValue } from '@mantine/hooks'
import { useState } from 'react'
import { createFileRoute } from '@tanstack/react-router'
import { TbPlus, TbSearch } from 'react-icons/tb'
import { DashboardLayout } from '@/frontend/components/DashboardLayout'
@@ -10,9 +12,12 @@ export const Route = createFileRoute('/apps/')({
})
function AppsPage() {
const [search, setSearch] = useState('')
const [debouncedSearch] = useDebouncedValue(search, 300)
const { data: apps, isLoading } = useQuery({
queryKey: ['apps'],
queryFn: () => fetch('/api/apps').then((r) => r.json()),
queryKey: ['apps', debouncedSearch],
queryFn: () => fetch(`/api/apps?search=${encodeURIComponent(debouncedSearch)}`).then((r) => r.json()),
})
return (
@@ -24,14 +29,14 @@ function AppsPage() {
<Title order={2} className="gradient-text">Applications</Title>
<Text size="sm" c="dimmed">Manage and monitor all your mobile applications from one place.</Text>
</Stack>
<Button
{/* <Button
variant="gradient"
gradient={{ from: '#2563EB', to: '#7C3AED', deg: 135 }}
leftSection={<TbPlus size={18} />}
radius="md"
>
Add New Application
</Button>
</Button> */}
</Group>
<Group>
@@ -40,6 +45,8 @@ function AppsPage() {
leftSection={<TbSearch size={16} />}
style={{ flex: 1 }}
radius="md"
value={search}
onChange={(e) => setSearch(e.currentTarget.value)}
/>
</Group>

View File

@@ -27,7 +27,6 @@ export const Route = createFileRoute('/dashboard')({
queryFn: () => fetch('/api/auth/session', { credentials: 'include' }).then((r) => r.json()),
})
if (!data?.user) throw redirect({ to: '/login' })
if (data.user.role !== 'SUPER_ADMIN') throw redirect({ to: '/profile' })
} catch (e) {
if (e instanceof Error) throw redirect({ to: '/login' })
throw e

View File

@@ -1,3 +1,4 @@
import { useLogin } from '@/frontend/hooks/useAuth'
import {
Alert,
Button,
@@ -13,8 +14,7 @@ import {
import { createFileRoute, redirect } from '@tanstack/react-router'
import { useState } from 'react'
import { FcGoogle } from 'react-icons/fc'
import { TbAlertCircle, TbLogin, TbLock, TbMail } from 'react-icons/tb'
import { useLogin } from '@/frontend/hooks/useAuth'
import { TbAlertCircle, TbLock, TbLogin, TbMail } from 'react-icons/tb'
export const Route = createFileRoute('/login')({
validateSearch: (search: Record<string, unknown>): { error?: string } => ({
@@ -27,7 +27,7 @@ export const Route = createFileRoute('/login')({
queryFn: () => fetch('/api/auth/session', { credentials: 'include' }).then((r) => r.json()),
})
if (data?.user) {
throw redirect({ to: data.user.role === 'SUPER_ADMIN' ? '/dashboard' : '/profile' })
throw redirect({ to: '/dashboard' })
}
} catch (e) {
if (e instanceof Error) return
@@ -57,12 +57,6 @@ function LoginPage() {
Login
</Title>
<Text c="dimmed" size="sm" ta="center">
Demo: <strong>superadmin@example.com</strong> / <strong>superadmin123</strong>
<br />
or: <strong>user@example.com</strong> / <strong>user123</strong>
</Text>
{(login.isError || searchError) && (
<Alert icon={<TbAlertCircle size={16} />} color="red" variant="light">
{login.isError ? login.error.message : 'Google login failed, please try again.'}
@@ -95,18 +89,6 @@ function LoginPage() {
>
Sign in
</Button>
<Divider label="or" labelPosition="center" />
<Button
component="a"
href="/api/auth/google"
fullWidth
variant="default"
leftSection={<FcGoogle size={18} />}
>
Login with Google
</Button>
</Stack>
</form>
</Paper>

View File

@@ -30,9 +30,8 @@ export const Route = createFileRoute('/profile')({
})
const roleBadgeColor: Record<string, string> = {
USER: 'blue',
ADMIN: 'violet',
SUPER_ADMIN: 'red',
DEVELOPER: 'red',
}
function ProfilePage() {

View File

@@ -59,20 +59,15 @@ const getRoleColor = (role: string) => {
}
const roles = [
{
name: 'SUPER_ADMIN',
color: 'red',
permissions: ['Full Access', 'User Mgmt', 'Role Mgmt', 'App Config', 'Logs & Errors']
},
{
name: 'DEVELOPER',
color: 'brand-blue',
permissions: ['View All Apps', 'Manage Assigned App', 'View Logs', 'Resolve Errors', 'Village Setup']
color: 'red',
permissions: ['Full Access', 'Error Feedback', 'Error Management', 'App Version Management', 'User Management']
},
{
name: 'QA',
name: 'ADMIN',
color: 'orange',
permissions: ['View All Apps', 'View Logs', 'Report Errors', 'Test App Features']
permissions: ['View All Apps', 'View Logs', 'Report Errors']
},
]
@@ -414,10 +409,8 @@ function UsersPage() {
<Select
label="Role"
data={[
{ value: 'USER', label: 'User' },
{ value: 'ADMIN', label: 'Admin' },
{ value: 'DEVELOPER', label: 'Developer' },
{ value: 'SUPER_ADMIN', label: 'Super Admin' },
]}
value={createForm.role}
onChange={(val) => setCreateForm({ ...createForm, role: val || 'USER' })}
@@ -461,10 +454,8 @@ function UsersPage() {
<Select
label="Role"
data={[
{ value: 'USER', label: 'User' },
{ value: 'ADMIN', label: 'Admin' },
{ value: 'DEVELOPER', label: 'Developer' },
{ value: 'SUPER_ADMIN', label: 'Super Admin' },
]}
value={editForm.role}
onChange={(val) => setEditForm({ ...editForm, role: val || 'USER' })}