refactor: standardize theme colors, update UI components, and refine auth redirection logic
This commit is contained in:
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import { Drawer, Text, Stack, NavLink, ThemeIcon, ActionIcon, ScrollArea, Group } from '@repo/ui/components';
|
import { Drawer, Text, Stack, NavLink, ThemeIcon, ActionIcon, ScrollArea, Group } from '@repo/ui/components';
|
||||||
import { useAppEvent } from '@repo/core-events';
|
import { useAppEvent } from '@repo/core-events';
|
||||||
import { useTranslation } from '@repo/core-i18n';
|
import { useTranslation } from '@repo/core-i18n';
|
||||||
import { Bookmark, Trash2 } from 'lucide-react';
|
import { Bookmark, Trash } from 'lucide-react';
|
||||||
import { LAYOUT_EVENTS } from '../../../../../core/constants/events';
|
import { LAYOUT_EVENTS } from '../../../../../core/constants/events';
|
||||||
import { appDatabase, AppDatabaseKey } from '../../../../../core/storage/local';
|
import { appDatabase, AppDatabaseKey } from '../../../../../core/storage/local';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
@@ -85,11 +85,11 @@ export function BookmarkDrawer() {
|
|||||||
<Group justify="flex-end" px="md" py="xs">
|
<Group justify="flex-end" px="md" py="xs">
|
||||||
<Text
|
<Text
|
||||||
size="xs"
|
size="xs"
|
||||||
c="red"
|
c="var(--mantine-color-error-6)"
|
||||||
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '4px' }}
|
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '4px' }}
|
||||||
onClick={handleClearAll}
|
onClick={handleClearAll}
|
||||||
>
|
>
|
||||||
<Trash2 size={12} /> {t('bookmark:clearAll')}
|
<Trash size={12} /> {t('bookmark:clearAll')}
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<ScrollArea flex={1} type="scroll" px="xs" py="xs" pb={'xl'}>
|
<ScrollArea flex={1} type="scroll" px="xs" py="xs" pb={'xl'}>
|
||||||
@@ -120,7 +120,7 @@ export function BookmarkDrawer() {
|
|||||||
rightSection={
|
rightSection={
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
color="red"
|
color="var(--mantine-color-error-6)"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -128,7 +128,7 @@ export function BookmarkDrawer() {
|
|||||||
}}
|
}}
|
||||||
aria-label={t('bookmark:removeItem')}
|
aria-label={t('bookmark:removeItem')}
|
||||||
>
|
>
|
||||||
<Trash2 size={14} />
|
<Trash size={14} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
}
|
}
|
||||||
styles={{
|
styles={{
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default function HeaderLayout() {
|
|||||||
{t('common:cancel')}
|
{t('common:cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
color="red"
|
color="var(--mantine-color-error-6)"
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
modals.close('logout-confirmation');
|
modals.close('logout-confirmation');
|
||||||
@@ -237,7 +237,11 @@ export default function HeaderLayout() {
|
|||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
|
|
||||||
{/* Sign Out Section */}
|
{/* Sign Out Section */}
|
||||||
<Menu.Item color="red" leftSection={<LogOut size={14} />} onClick={() => handleLogout()}>
|
<Menu.Item
|
||||||
|
color="var(--mantine-color-error-6)"
|
||||||
|
leftSection={<LogOut size={14} />}
|
||||||
|
onClick={() => handleLogout()}
|
||||||
|
>
|
||||||
{t('common:signOut')}
|
{t('common:signOut')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
} from '@repo/ui/components';
|
} from '@repo/ui/components';
|
||||||
import { useAppEvent } from '@repo/core-events';
|
import { useAppEvent } from '@repo/core-events';
|
||||||
import { useTranslation } from '@repo/core-i18n';
|
import { useTranslation } from '@repo/core-i18n';
|
||||||
import { History, Clock, Trash2 } from 'lucide-react';
|
import { History, Clock, Trash } from 'lucide-react';
|
||||||
import { LAYOUT_EVENTS } from '../../../../../core/constants/events';
|
import { LAYOUT_EVENTS } from '../../../../../core/constants/events';
|
||||||
import { appDatabase, AppDatabaseKey } from '../../../../../core/storage/local';
|
import { appDatabase, AppDatabaseKey } from '../../../../../core/storage/local';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
@@ -129,7 +129,7 @@ export function HistoryDrawer() {
|
|||||||
<Menu.Target>
|
<Menu.Target>
|
||||||
<UnstyledButton>
|
<UnstyledButton>
|
||||||
<Group gap={6} c="dimmed" style={{ transition: 'color 0.2s' }}>
|
<Group gap={6} c="dimmed" style={{ transition: 'color 0.2s' }}>
|
||||||
<Trash2 size={14} />
|
<Trash size={14} />
|
||||||
<Text size="xs" fw={500} style={{ cursor: 'pointer' }}>
|
<Text size="xs" fw={500} style={{ cursor: 'pointer' }}>
|
||||||
{t('history:clearRange')}
|
{t('history:clearRange')}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -142,7 +142,11 @@ export function HistoryDrawer() {
|
|||||||
<Menu.Item onClick={() => handleClearRange('lastHour')}>{t('history:ranges.lastHour')}</Menu.Item>
|
<Menu.Item onClick={() => handleClearRange('lastHour')}>{t('history:ranges.lastHour')}</Menu.Item>
|
||||||
<Menu.Item onClick={() => handleClearRange('today')}>{t('history:ranges.today')}</Menu.Item>
|
<Menu.Item onClick={() => handleClearRange('today')}>{t('history:ranges.today')}</Menu.Item>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item color="red" leftSection={<Trash2 size={14} />} onClick={() => handleClearRange('allTime')}>
|
<Menu.Item
|
||||||
|
color="var(--mantine-color-error-6)"
|
||||||
|
leftSection={<Trash size={14} />}
|
||||||
|
onClick={() => handleClearRange('allTime')}
|
||||||
|
>
|
||||||
{t('history:ranges.allTime')}
|
{t('history:ranges.allTime')}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
@@ -177,7 +181,7 @@ export function HistoryDrawer() {
|
|||||||
rightSection={
|
rightSection={
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
color="red"
|
color="var(--mantine-color-error-6)"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -185,7 +189,7 @@ export function HistoryDrawer() {
|
|||||||
}}
|
}}
|
||||||
aria-label={t('history:removeItem')}
|
aria-label={t('history:removeItem')}
|
||||||
>
|
>
|
||||||
<Trash2 size={14} />
|
<Trash size={14} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
}
|
}
|
||||||
styles={{
|
styles={{
|
||||||
|
|||||||
+8
-1
@@ -67,7 +67,14 @@ export function NotificationDropdown({ children }: NotificationDropdownProps) {
|
|||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
{/* Trigger wrapped around the Bell icon */}
|
{/* Trigger wrapped around the Bell icon */}
|
||||||
<Box onClick={() => setOpened((o) => !o)} style={{ cursor: 'pointer' }}>
|
<Box onClick={() => setOpened((o) => !o)} style={{ cursor: 'pointer' }}>
|
||||||
<Indicator inline size={9} offset={4} color="red" withBorder disabled={unreadCount === 0}>
|
<Indicator
|
||||||
|
inline
|
||||||
|
size={9}
|
||||||
|
offset={4}
|
||||||
|
color="var(--mantine-color-error-6)"
|
||||||
|
withBorder
|
||||||
|
disabled={unreadCount === 0}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export default function SettingPage() {
|
|||||||
<Button variant="default" onClick={handleCancelSwitch}>
|
<Button variant="default" onClick={handleCancelSwitch}>
|
||||||
{t('setting:unsaved.cancel')}
|
{t('setting:unsaved.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="red" onClick={handleDiscardChanges}>
|
<Button color="var(--mantine-color-error-6)" onClick={handleDiscardChanges}>
|
||||||
{t('setting:unsaved.discard')}
|
{t('setting:unsaved.discard')}
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -25,15 +25,21 @@ export async function terminateAuthSession(options: TerminateOptions = {}) {
|
|||||||
*/
|
*/
|
||||||
let loginUrl = '/auth/login';
|
let loginUrl = '/auth/login';
|
||||||
|
|
||||||
if (preserveRedirect) {
|
// Check if the current page is NOT the login page
|
||||||
const currentPath = window.location.pathname + window.location.search;
|
const isNotLoginPage = !window.location.pathname.includes('/auth/login');
|
||||||
loginUrl += `?redirect=${encodeURIComponent(currentPath)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (isNotLoginPage) {
|
||||||
* Redirect without saving history to prevent infinite back-loops
|
// Set redirect parameters only if requested AND the user is not currently on the login page
|
||||||
*/
|
if (preserveRedirect) {
|
||||||
window.location.replace(loginUrl);
|
const currentPath = window.location.pathname + window.location.search;
|
||||||
|
loginUrl += `?redirect=${encodeURIComponent(currentPath)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect without saving history to prevent infinite back-loops
|
||||||
|
*/
|
||||||
|
window.location.replace(loginUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initiateAuthSession(respLogin: any) {
|
export async function initiateAuthSession(respLogin: any) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"save": "Simpan",
|
"save": "Simpan",
|
||||||
"cancel": "Batal",
|
"cancel": "Batal",
|
||||||
"success": "Sukses",
|
"success": "Sukses",
|
||||||
"error": "Galat",
|
"error": "Error",
|
||||||
"settings": "Pengaturan",
|
"settings": "Pengaturan",
|
||||||
"loading": "Memuat",
|
"loading": "Memuat",
|
||||||
"delete": "Hapus",
|
"delete": "Hapus",
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"successTitle": "Berhasil",
|
"successTitle": "Berhasil",
|
||||||
"errorTitle": "Galat",
|
"errorTitle": "Error",
|
||||||
"saveSuccess": "Data berhasil disimpan",
|
"saveSuccess": "Data berhasil disimpan",
|
||||||
"deleteSuccess": "Data berhasil dihapus",
|
"deleteSuccess": "Data berhasil dihapus",
|
||||||
"actionSuccess": "{{action}} berhasil diselesaikan",
|
"actionSuccess": "{{action}} berhasil diselesaikan",
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export function EnterpriseFormPageProvider<E extends BaseEntity = BaseEntity>(pr
|
|||||||
notifications.show({
|
notifications.show({
|
||||||
title: t('common:notifications.errorTitle'),
|
title: t('common:notifications.errorTitle'),
|
||||||
message: message ?? error?.message,
|
message: message ?? error?.message,
|
||||||
color: 'red',
|
color: 'var(--mantine-color-error-6)',
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@@ -250,7 +250,7 @@ export function EnterpriseFormPageProvider<E extends BaseEntity = BaseEntity>(pr
|
|||||||
notifications.show({
|
notifications.show({
|
||||||
title: t('common:notifications.errorTitle'),
|
title: t('common:notifications.errorTitle'),
|
||||||
message: message ?? error?.message,
|
message: message ?? error?.message,
|
||||||
color: 'red',
|
color: 'var(--mantine-color-error-6)',
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setIsSaving(false);
|
setIsSaving(false);
|
||||||
@@ -355,7 +355,7 @@ export function EnterpriseFormPageProvider<E extends BaseEntity = BaseEntity>(pr
|
|||||||
{t('common:confirmDialog.leave.cancel')}
|
{t('common:confirmDialog.leave.cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
color="red"
|
color="var(--mantine-color-error-6)"
|
||||||
size="xs"
|
size="xs"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
actionTaken = true;
|
actionTaken = true;
|
||||||
|
|||||||
@@ -35,11 +35,17 @@ export function ThemeProvider({ children, colorScheme = 'light', density = 'comp
|
|||||||
black: '#1A1B1E',
|
black: '#1A1B1E',
|
||||||
colors: {
|
colors: {
|
||||||
brand: brandColors,
|
brand: brandColors,
|
||||||
|
dark: darkColors,
|
||||||
|
|
||||||
error: errorColors,
|
error: errorColors,
|
||||||
warning: warningColors,
|
warning: warningColors,
|
||||||
success: successColors,
|
success: successColors,
|
||||||
info: infoColors,
|
info: infoColors,
|
||||||
dark: darkColors,
|
|
||||||
|
red: errorColors,
|
||||||
|
yellow: warningColors,
|
||||||
|
green: successColors,
|
||||||
|
blue: infoColors,
|
||||||
},
|
},
|
||||||
primaryColor: 'brand',
|
primaryColor: 'brand',
|
||||||
fontFamily: typography.fontFamily,
|
fontFamily: typography.fontFamily,
|
||||||
|
|||||||
@@ -12,57 +12,56 @@ export const brandColors: MantineColorsTuple = [
|
|||||||
'#321a7a', // 800
|
'#321a7a', // 800
|
||||||
'#1b0f4a', // 900
|
'#1b0f4a', // 900
|
||||||
];
|
];
|
||||||
|
|
||||||
export const errorColors: MantineColorsTuple = [
|
export const errorColors: MantineColorsTuple = [
|
||||||
'#fef2f2',
|
'#fef3f2', // 0: 50
|
||||||
'#fee2e2',
|
'#fee4e2', // 1: 100
|
||||||
'#fecaca',
|
'#fecdca', // 2: 200
|
||||||
'#fca5a5',
|
'#fda29b', // 3: 300
|
||||||
'#f87171',
|
'#f97066', // 4: 400
|
||||||
'#ef4444',
|
'#f04438', // 5: 500
|
||||||
'#dc2626',
|
'#d92d20', // 6: 600 (Primary)
|
||||||
'#b91c1c',
|
'#b42318', // 7: 700
|
||||||
'#991b1b',
|
'#912018', // 8: 800
|
||||||
'#7f1d1d',
|
'#7a271a', // 9: 900
|
||||||
];
|
];
|
||||||
|
|
||||||
export const warningColors: MantineColorsTuple = [
|
export const warningColors: MantineColorsTuple = [
|
||||||
'#fffbeb',
|
'#fffdf5', // 0: 50
|
||||||
'#fef3c7',
|
'#fff9db', // 1: 100
|
||||||
'#fde68a',
|
'#fff0b3', // 2: 200
|
||||||
'#fcd34d',
|
'#ffe480', // 3: 300
|
||||||
'#fbbf24',
|
'#ffd64d', // 4: 400
|
||||||
'#f59e0b',
|
'#ffc71a', // 5: 500
|
||||||
'#d97706',
|
'#ffb800', // 6: 600 (Primary)
|
||||||
'#b45309',
|
'#d19200', // 7: 700
|
||||||
'#92400e',
|
'#a67000', // 8: 800
|
||||||
'#78350f',
|
'#7a5000', // 9: 900
|
||||||
];
|
];
|
||||||
|
|
||||||
export const successColors: MantineColorsTuple = [
|
export const successColors: MantineColorsTuple = [
|
||||||
'#f0fdf4',
|
'#f3fcf0', // 0: 50
|
||||||
'#dcfce7',
|
'#e3f8dc', // 1: 100
|
||||||
'#bbf7d0',
|
'#c6f0b7', // 2: 200
|
||||||
'#86efac',
|
'#a0e589', // 3: 300
|
||||||
'#4ade80',
|
'#7bd760', // 4: 400
|
||||||
'#22c55e',
|
'#5ace3c', // 5: 500
|
||||||
'#16a34a',
|
'#3ec300', // 6: 600 (Primary)
|
||||||
'#15803d',
|
'#309b00', // 7: 700
|
||||||
'#166534',
|
'#267b00', // 8: 800
|
||||||
'#14532d',
|
'#206505', // 9: 900
|
||||||
];
|
];
|
||||||
|
|
||||||
export const infoColors: MantineColorsTuple = [
|
export const infoColors: MantineColorsTuple = [
|
||||||
'#f0f9ff',
|
'#eef7ff', // 0: 50
|
||||||
'#e0f2fe',
|
'#d9efff', // 1: 100
|
||||||
'#bae6fd',
|
'#b0ddff', // 2: 200
|
||||||
'#7dd3fc',
|
'#82c9ff', // 3: 300
|
||||||
'#38bdf8',
|
'#54b5ff', // 4: 400
|
||||||
'#0ea5e9',
|
'#26a1ff', // 5: 500
|
||||||
'#0284c7',
|
'#0094ff', // 6: 600 (Primary)
|
||||||
'#0369a1',
|
'#0079d6', // 7: 700
|
||||||
'#075985',
|
'#0060ad', // 8: 800
|
||||||
'#0c4a6e',
|
'#004b87', // 9: 900
|
||||||
];
|
];
|
||||||
|
|
||||||
export const grayColors: MantineColorsTuple = [
|
export const grayColors: MantineColorsTuple = [
|
||||||
@@ -104,4 +103,3 @@ export const darkColors: MantineColorsTuple = [
|
|||||||
'#151828', // 8 – Deep background (sidebar, nav)
|
'#151828', // 8 – Deep background (sidebar, nav)
|
||||||
'#0F1120', // 9 – Deepest background
|
'#0F1120', // 9 – Deepest background
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user