Former-commit-id: 44b553bd067cd5ad00ca0b97a7173decb3356263 [formerly d2ab1d1336bd562b454d7d1f33554e4ad4339e22] [formerly 8e464743040679a782f8bbd644f3943068a5d6da [formerly d9d751bcc11a4b98db62d2669a876734d286d5de]]
Former-commit-id: 266f7b659a1b944ba5cd66caef3053ea9208d4fa [formerly f8f75b017f7332a2da7f9ae2f915413319415480]
Former-commit-id: 2e3ce847f7d7fbbfcf2ff55f196cbe3cec0c74f6
This commit is contained in:
Melvin Chia
2025-05-19 09:23:14 +08:00
parent 70775f615e
commit a6a982eeff
62 changed files with 577 additions and 423 deletions

View File

@@ -1,5 +1,11 @@
# Change Log
### 📌 **dev 25w21 (5/19/2025 - 5/26/2025)**
- **Account Settings**: Renamed the folder from `Account` to `Account Settings` for better clarity.
- **Code**: Module route configs are now stored in a separate file in each module directory and loaded dynamically in the routing mechanism.
- **Code**: Massive mechanism refactor to load module routes dynamically.
- **Code**: Renamed `layout` folder to `routes` for better clarity.
### 📌 **dev 25w20 (5/12/2025 - 5/19/2025)**
- **Wallet**: Fixed a bug where the order of the transactions doesn't update when the user update the date of a transaction.
- **Wallet**: Fixed a critical bug where the page will crash when user tries to load the dashboard.

View File

@@ -0,0 +1,13 @@
import { IconAward } from '@tabler/icons-react'
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Achievements',
icon: <IconAward />,
routes: {
achievements: lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,12 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { lazy } from 'react'
export default {
name: 'Books Library',
icon: 'tabler:books',
provider: lazy(() => import('./providers/BooksLibraryProvider')),
routes: {
'': lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,13 @@
import { IconCalendar } from '@tabler/icons-react'
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Calendar',
icon: <IconCalendar />,
routes: {
calendar: lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,11 @@
import { IconCode } from '@tabler/icons-react'
import { lazy } from 'react'
export default {
name: 'Code Time',
icon: <IconCode />,
routes: {
'code-time': lazy(() => import('.'))
},
togglable: true
}

View File

@@ -0,0 +1,12 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Currency Converter',
icon: 'tabler:currency-dollar',
routes: {
'currency-converter': lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,12 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Guitar Tabs',
icon: 'mingcute:guitar-line',
routes: {
'guitar-tabs': lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,15 @@
import { IconBulb } from '@tabler/icons-react'
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Idea Box',
provider: lazy(() => import('./providers/IdeaBoxProvider')),
icon: <IconBulb />,
routes: {
'': lazy(() => import('./pages/Containers')),
':id/*': lazy(() => import('./pages/Ideas'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,14 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Moment Vault',
icon: 'tabler:history',
hasAI: true,
routes: {
'moment-vault': lazy(() => import('.'))
},
togglable: true,
requiredAPIKeys: ['openai']
} satisfies ModuleConfig

View File

@@ -0,0 +1,13 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Movies',
icon: 'tabler:movie',
routes: {
movies: lazy(() => import('.'))
},
togglable: true,
requiredAPIKeys: ['tmdb']
} satisfies ModuleConfig

12
src/apps/Music/config.tsx Normal file
View File

@@ -0,0 +1,12 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Music',
icon: 'tabler:music',
routes: {
music: lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,13 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Passwords',
icon: 'tabler:key',
provider: lazy(() => import('./providers/PasswordsProvider')),
routes: {
'': lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,13 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Railway Map',
icon: 'uil:subway',
provider: lazy(() => import('./providers/RailwayMapProvider')),
routes: {
'': lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,12 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Sudoku',
icon: 'uil:table',
routes: {
sudoku: lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,15 @@
import { IconListCheck } from '@tabler/icons-react'
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Todo List',
icon: <IconListCheck />,
routes: {
'todo-list': lazy(() => import('@apps/TodoList'))
},
togglable: true,
hasAI: true,
requiredAPIKeys: ['groq']
} satisfies ModuleConfig

View File

@@ -0,0 +1,27 @@
import { lazy } from 'react'
import { Navigate } from 'react-router'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Virtual Wardrobe',
icon: 'tabler:shirt',
subsection: [
{
name: 'Virtual Wardrobe Clothes',
icon: 'tabler:shirt',
path: 'clothes'
},
{
name: 'Virtual Wardrobe Outfits',
icon: 'tabler:layout',
path: 'outfits'
}
],
routes: {
'virtual-wardrobe': () => <Navigate to="/virtual-wardrobe/clothes" />,
'virtual-wardrobe/clothes': lazy(() => import('./pages/Clothes')),
'virtual-wardrobe/outfits': lazy(() => import('./pages/Outfits'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,40 @@
import {
IconArrowsExchange,
IconBook,
IconCurrencyDollar,
IconDashboard,
IconFileText,
IconWallet
} from '@tabler/icons-react'
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Wallet',
icon: <IconCurrencyDollar />,
hasAI: true,
subsection: [
{ name: 'Dashboard', icon: <IconDashboard />, path: '' },
{
name: 'Transactions',
icon: <IconArrowsExchange />,
path: 'transactions'
},
{ name: 'Assets', icon: <IconWallet />, path: 'assets' },
{ name: 'Ledgers', icon: <IconBook />, path: 'ledgers' },
{
name: 'Financial Statements',
icon: <IconFileText />,
path: 'statements'
}
],
routes: {
wallet: lazy(() => import('./pages/Dashboard')),
'wallet/transactions': lazy(() => import('./pages/Transactions')),
'wallet/assets': lazy(() => import('./pages/Assets')),
'wallet/ledgers': lazy(() => import('./pages/Ledgers')),
'wallet/statements': lazy(() => import('./pages/Statements'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,14 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Wishlist',
icon: 'tabler:heart',
routes: {
wishlist: lazy(() => import('./pages/WishlistList')),
'wishlist/:id': lazy(() => import('./pages/WishlistEntries'))
},
togglable: true,
hasAI: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,14 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Youtube Summarizer',
icon: 'tabler:brand-youtube',
routes: {
'youtube-summarizer': lazy(() => import('.'))
},
togglable: true,
requiredAPIKeys: ['groq'],
hasAI: true
} satisfies ModuleConfig

View File

@@ -0,0 +1,12 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../core/routes/interfaces/routes_interfaces'
export default {
name: 'Youtube Videos',
icon: 'tabler:brand-youtube',
routes: {
'youtube-videos': lazy(() => import('.'))
},
togglable: true
} satisfies ModuleConfig

View File

@@ -22,7 +22,7 @@ import '@lifeforge/ui/dist/index.css'
import './i18n'
import './index.css'
import AppRouter from './layout/index.tsx'
import AppRouter from './routes/index.tsx'
dayjs.extend(duration)
dayjs.extend(isBetween)

View File

@@ -1,382 +0,0 @@
import {
IconArrowsExchange,
IconAward,
IconBook,
IconBooks,
IconBulb,
IconCalendar,
IconCode,
IconCurrencyDollar,
IconDashboard,
IconFileText,
IconHeart,
IconHistory,
IconInfoCircle,
IconKey,
IconLayout,
IconListCheck,
IconMovie,
IconMusic,
IconPalette,
IconPassword,
IconPlug,
IconServer,
IconShirt,
IconUserCog,
IconWallet
} from '@tabler/icons-react'
import { lazy } from 'react'
import { Navigate } from 'react-router'
import { RouteCategory } from './layout/interfaces/routes_interfaces'
export const ROUTES: RouteCategory[] = [
{
title: '',
items: [
{
name: 'Dashboard',
icon: <IconDashboard />,
routes: {
dashboard: lazy(() => import('./pages/Dashboard'))
},
togglable: false
}
]
},
{
title: 'Productivity',
items: [
{
name: 'Idea Box',
provider: lazy(() => import('@apps/IdeaBox/providers/IdeaBoxProvider')),
icon: <IconBulb />,
routes: {
'': lazy(() => import('@apps/IdeaBox/pages/Containers')),
':id/*': lazy(() => import('@apps/IdeaBox/pages/Ideas'))
},
togglable: true
},
{
name: 'Todo List',
icon: <IconListCheck />,
routes: {
'todo-list': lazy(() => import('@apps/TodoList'))
},
togglable: true,
hasAI: true,
requiredAPIKeys: ['groq']
},
{
name: 'Calendar',
icon: <IconCalendar />,
routes: {
calendar: lazy(() => import('@apps/Calendar'))
},
togglable: true
},
{
name: 'Code Time',
icon: <IconCode />,
routes: {
'code-time': lazy(() => import('@apps/CodeTime'))
},
togglable: true
}
]
},
{
title: 'Study',
items: []
},
{
title: 'Lifestyle',
items: [
{
name: 'Moment Vault',
icon: <IconHistory />,
hasAI: true,
routes: {
'moment-vault': lazy(() => import('@apps/MomentVault'))
},
togglable: true,
requiredAPIKeys: ['openai']
},
{
name: 'Achievements',
icon: <IconAward />,
routes: {
achievements: lazy(() => import('@apps/Achievements'))
},
togglable: true
},
{
name: 'Virtual Wardrobe',
icon: <IconShirt />,
subsection: [
{
name: 'Virtual Wardrobe Clothes',
icon: <IconShirt />,
path: 'clothes'
},
{
name: 'Virtual Wardrobe Outfits',
icon: <IconLayout />,
path: 'outfits'
}
],
routes: {
'virtual-wardrobe': () => <Navigate to="/virtual-wardrobe/clothes" />,
'virtual-wardrobe/clothes': lazy(
() => import('@apps/VirtualWardrobe/pages/Clothes')
),
'virtual-wardrobe/outfits': lazy(
() => import('@apps/VirtualWardrobe/pages/Outfits')
)
},
togglable: true
},
{
name: 'Movies',
icon: <IconMovie />,
routes: {
movies: lazy(() => import('@apps/Movies'))
},
togglable: true,
requiredAPIKeys: ['tmdb']
}
]
},
{
title: 'Finance',
items: [
{
name: 'Wallet',
icon: <IconCurrencyDollar />,
hasAI: true,
subsection: [
{ name: 'Dashboard', icon: <IconDashboard />, path: '' },
{
name: 'Transactions',
icon: <IconArrowsExchange />,
path: 'transactions'
},
{ name: 'Assets', icon: <IconWallet />, path: 'assets' },
{ name: 'Ledgers', icon: <IconBook />, path: 'ledgers' },
{
name: 'Financial Statements',
icon: <IconFileText />,
path: 'statements'
}
],
routes: {
wallet: lazy(() => import('@apps/Wallet/pages/Dashboard')),
'wallet/transactions': lazy(
() => import('@apps/Wallet/pages/Transactions')
),
'wallet/assets': lazy(() => import('@apps/Wallet/pages/Assets')),
'wallet/ledgers': lazy(() => import('@apps/Wallet/pages/Ledgers')),
'wallet/statements': lazy(
() => import('@apps/Wallet/pages/Statements')
)
},
togglable: true
},
{
name: 'Wishlist',
icon: <IconHeart />,
routes: {
wishlist: lazy(() => import('@apps/Wishlist/pages/WishlistList')),
'wishlist/:id': lazy(
() => import('@apps/Wishlist/pages/WishlistEntries')
)
},
togglable: true,
hasAI: true
}
]
},
{
title: 'Storage',
items: [
{
name: 'Books Library',
icon: <IconBooks />,
provider: lazy(
() => import('@apps/BooksLibrary/providers/BooksLibraryProvider')
),
routes: {
'': lazy(() => import('@apps/BooksLibrary'))
},
togglable: true
},
{
name: 'Music',
icon: <IconMusic />,
routes: {
music: lazy(() => import('@apps/Music'))
},
togglable: true
},
{
name: 'Guitar Tabs',
icon: 'mingcute:guitar-line',
routes: {
'guitar-tabs': lazy(() => import('@apps/GuitarTabs'))
},
togglable: true
},
{
name: 'Youtube Videos',
icon: 'tabler:brand-youtube',
routes: {
'youtube-videos': lazy(() => import('@apps/YoutubeVideos'))
},
togglable: true
}
]
},
{
title: 'Confidential',
items: [
{
name: 'Passwords',
icon: <IconKey />,
provider: lazy(
() => import('@apps/Passwords/providers/PasswordsProvider')
),
routes: {
'': lazy(() => import('@apps/Passwords'))
},
togglable: true
},
{
name: 'API Keys',
icon: <IconPassword />,
routes: {
'api-keys': lazy(() => import('./pages/APIKeys'))
},
togglable: false
}
]
},
{
title: 'Information',
items: [
{
name: 'Railway Map',
icon: 'uil:subway',
provider: lazy(
() => import('@apps/RailwayMap/providers/RailwayMapProvider')
),
routes: {
'': lazy(() => import('@apps/RailwayMap'))
},
togglable: true
}
]
},
{
title: 'Utilities',
items: [
{
name: 'Sudoku',
icon: 'uil:table',
routes: {
sudoku: lazy(() => import('@apps/Sudoku'))
},
togglable: true
},
{
name: 'Currency Converter',
icon: <IconCurrencyDollar />,
routes: {
'currency-converter': lazy(() => import('@apps/CurrencyConverter'))
},
togglable: true
},
{
name: 'Youtube Summarizer',
icon: 'tabler:brand-youtube',
routes: {
'youtube-summarizer': lazy(() => import('@apps/YoutubeSummarizer'))
},
togglable: true,
requiredAPIKeys: ['groq'],
hasAI: true
}
]
},
{
title: 'Settings',
items: [
{
name: 'Personalization',
icon: <IconPalette />,
routes: {
personalization: lazy(() => import('./pages/Personalization'))
},
togglable: false
},
{
name: 'Modules',
icon: <IconPlug />,
routes: {
modules: lazy(() => import('@apps/Modules'))
},
togglable: false
},
{
name: 'Server Status',
icon: <IconServer />,
routes: {
'server-status': lazy(() => import('./pages/ServerStatus'))
},
togglable: false
}
]
},
{
title: 'sso',
items: [
{
name: 'Localization Manager',
icon: 'mingcute:translate-line',
routes: {
'localization-manager': lazy(
() => import('./pages/LocalizationManager')
)
},
togglable: false
}
]
},
{
title: '',
items: [
{
name: 'Documentation',
icon: <IconInfoCircle />,
routes: {
documentation: () => {
window.location.href =
'https://docs.lifeforge.melvinchia.dev/getting-started/introduction'
return <Navigate to="/" />
}
},
togglable: false
},
{
name: 'Account Settings',
icon: <IconUserCog />,
routes: {
account: lazy(() => import('./pages/Account'))
},
togglable: false,
hidden: true
}
]
}
]
export default ROUTES

View File

@@ -0,0 +1,13 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { IconUserCog } from '@tabler/icons-react'
import { lazy } from 'react'
export default {
name: 'Account Settings',
icon: <IconUserCog />,
routes: {
account: lazy(() => import('.'))
},
togglable: false,
hidden: true
} satisfies ModuleConfig

View File

@@ -7,7 +7,7 @@ import PasswordColumn from './components/PasswordColumn'
import TwoFAColumn from './components/TwoFAColumn'
import { AccountSettingsModals } from './modals'
function Account() {
function AccountSettings() {
useModalsEffect(AccountSettingsModals)
return (
@@ -35,4 +35,4 @@ function Account() {
)
}
export default Account
export default AccountSettings

View File

@@ -0,0 +1,12 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { IconDashboard } from '@tabler/icons-react'
import { lazy } from 'react'
export default {
name: 'Dashboard',
icon: <IconDashboard />,
routes: {
dashboard: lazy(() => import('.'))
},
togglable: false
} satisfies ModuleConfig

View File

@@ -0,0 +1,16 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { IconInfoCircle } from '@tabler/icons-react'
import { Navigate } from 'react-router'
export default {
name: 'Documentation',
icon: <IconInfoCircle />,
routes: {
documentation: () => {
window.location.href =
'https://docs.lifeforge.melvinchia.dev/getting-started/introduction'
return <Navigate to="/" />
}
},
togglable: false
} as ModuleConfig

View File

@@ -0,0 +1,12 @@
import { lazy } from 'react'
import { ModuleConfig } from '../../routes/interfaces/routes_interfaces'
export default {
name: 'Localization Manager',
icon: 'mingcute:translate-line',
routes: {
'localization-manager': lazy(() => import('.'))
},
togglable: false
} satisfies ModuleConfig

View File

@@ -1,3 +1,4 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { Icon } from '@iconify/react'
import clsx from 'clsx'
import _ from 'lodash'
@@ -8,14 +9,12 @@ import { Switch } from '@lifeforge/ui'
import useComponentBg from '@hooks/useComponentBg'
import { RouteItem } from '../../core/layout/interfaces/routes_interfaces'
function ModuleItem({
module,
enabled,
toggleModule
}: {
module: RouteItem
module: ModuleConfig
enabled: boolean
toggleModule: (moduleName: string) => void
}) {

View File

@@ -0,0 +1,11 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { lazy } from 'react'
export default {
name: 'Modules',
icon: 'tabler:plug',
routes: {
modules: lazy(() => import('.'))
},
togglable: false
} satisfies ModuleConfig

View File

@@ -1,3 +1,4 @@
import ROUTES from '@core/routes/Routes'
import _ from 'lodash'
import { useTranslation } from 'react-i18next'
import { toast } from 'react-toastify'
@@ -6,9 +7,8 @@ import { LoadingScreen, ModuleHeader, ModuleWrapper } from '@lifeforge/ui'
import fetchAPI from '@utils/fetchAPI'
import ROUTES from '../../core/Routes'
import { useAuth } from '../../core/pages/Auth/providers/AuthProvider'
import ModuleItem from './ModuleItem'
import { useAuth } from '../Auth/providers/AuthProvider'
import ModuleItem from './components/ModuleItem'
function Modules() {
const { t } = useTranslation('common.sidebar')

View File

@@ -0,0 +1,12 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { IconPalette } from '@tabler/icons-react'
import { lazy } from 'react'
export default {
name: 'Personalization',
icon: <IconPalette />,
routes: {
personalization: lazy(() => import('.'))
},
togglable: false
} satisfies ModuleConfig

View File

@@ -0,0 +1,12 @@
import { ModuleConfig } from '@core/routes/interfaces/routes_interfaces'
import { IconServer } from '@tabler/icons-react'
import { lazy } from 'react'
export default {
name: 'Server Status',
icon: <IconServer />,
routes: {
'server-status': lazy(() => import('.'))
},
togglable: false
} satisfies ModuleConfig

View File

@@ -0,0 +1,43 @@
import { ModuleCategory } from './interfaces/routes_interfaces'
import RouteItems from './routes.json'
export const ROUTES: ModuleCategory[] = []
const modules = import.meta.glob([
'../../apps/**/config.tsx',
'../pages/**/config.tsx'
])
function resolveAlias(path: string): string {
if (path.startsWith('@apps')) {
return path.replace('@apps', '../../apps')
}
if (path.startsWith('@core')) {
return path.replace('@core', '../pages')
}
return path
}
for (const route of RouteItems) {
const { title, items } = route
const importPromises = items.map(async item => {
const resolved = `${resolveAlias(item)}/config.tsx`
const importer = modules[resolved]
if (!importer) throw new Error(`Module not found: ${resolved}`)
const mod = (await importer()) as { default: any }
return mod.default
})
const awaitedRoutes = await Promise.all(importPromises)
ROUTES.push({
title,
items: awaitedRoutes
})
}
export default ROUTES

View File

@@ -3,7 +3,7 @@ import { Route } from 'react-router'
import { LoadingScreen, ModalManager } from '@lifeforge/ui'
import { RouteItem } from '../interfaces/routes_interfaces'
import { ModuleConfig } from '../../routes/interfaces/routes_interfaces'
import APIKeyStatusProvider from '../providers/APIKeyStatusProvider'
function ChildRoutesRenderer({
@@ -12,7 +12,7 @@ function ChildRoutesRenderer({
APIKeys = [],
t
}: {
routes: RouteItem['routes']
routes: ModuleConfig['routes']
t: any
isNested?: boolean
APIKeys?: string[]

View File

@@ -1,14 +1,14 @@
import MainApplication from '@core/routes/components/Layout'
import _ from 'lodash'
import { useTranslation } from 'react-i18next'
import { Route, Routes } from 'react-router'
import { NotFoundScreen } from '@lifeforge/ui'
import ROUTES from '../../Routes'
import Auth from '../../pages/Auth'
import { useAuth } from '../../pages/Auth/providers/AuthProvider'
import ROUTES from '../Routes'
import ChildRoutesRenderer from './ChildRoutesRenderer'
import MainApplication from './Layout'
function MainRoutesRenderer() {
const { t } = useTranslation('common.misc')
@@ -29,6 +29,8 @@ function MainRoutesRenderer() {
? (() => {
const Provider: React.FC = item.provider
console.log('Provider', Provider)
return (
<Route
key={item.name}

View File

@@ -10,8 +10,8 @@ import {
SidebarTitle
} from '@lifeforge/ui'
import ROUTES from '../../../Routes'
import { useAuth } from '../../../pages/Auth/providers/AuthProvider'
import ROUTES from '../../Routes'
function SidebarItems({ query }: { query: string }) {
const { userData } = useAuth()

View File

@@ -1,7 +1,7 @@
import _ from 'lodash'
import { useEffect } from 'react'
import ROUTES from '../../Routes'
import ROUTES from '../Routes'
function useTitleEffect() {
useEffect(() => {

View File

@@ -1,3 +1,4 @@
import MainRoutesRenderer from '@core/routes/components/MainRoutesRenderer'
import { useEffect } from 'react'
import { useLocation, useNavigate } from 'react-router'
@@ -12,7 +13,6 @@ import { useModalsEffect } from '@lifeforge/ui'
import Auth from '../pages/Auth'
import { useAuth } from '../pages/Auth/providers/AuthProvider'
import MainRoutesRenderer from './components/MainRoutesRenderer'
import useAuthEffect from './hooks/useAuthEffect'
import useTitleEffect from './hooks/useTitleEffect'

View File

@@ -1,4 +1,4 @@
export interface RouteItem {
export interface ModuleConfig {
name: string
icon: React.ReactElement | string
provider?:
@@ -20,7 +20,7 @@ export interface RouteItem {
hidden?: boolean
}
export interface RouteCategory {
export interface ModuleCategory {
title: string
items: RouteItem[]
items: ModuleConfig[]
}

View File

@@ -1,9 +1,9 @@
import MissingAPIKeyScreen from '@core/routes/components/MissingAPIKeyScreen'
import { ModuleWrapper, QueryWrapper } from '@lifeforge/ui'
import useAPIQuery from '@hooks/useAPIQuery'
import MissingAPIKeyScreen from '../components/MissingAPIKeyScreen'
function APIKeyStatusProvider({
APIKeys,
children

View File

@@ -0,0 +1,83 @@
[
{
"title": "",
"items": [
"@core/Dashboard"
]
},
{
"title": "Productivity",
"items": [
"@apps/IdeaBox",
"@apps/TodoList",
"@apps/Calendar",
"@apps/CodeTime"
]
},
{
"title": "Lifestyle",
"items": [
"@apps/MomentVault",
"@apps/VirtualWardrobe",
"@apps/Movies",
"@apps/Achievements"
]
},
{
"title": "Finance",
"items": [
"@apps/Wallet",
"@apps/Wishlist"
]
},
{
"title": "Storage",
"items": [
"@apps/BooksLibrary",
"@apps/Music",
"@apps/GuitarTabs",
"@apps/YoutubeVideos"
]
},
{
"title": "Confidential",
"items": [
"@apps/Passwords"
]
},
{
"title": "Information",
"items": [
"@apps/RailwayMap"
]
},
{
"title": "Utilities",
"items": [
"@apps/Sudoku",
"@apps/CurrencyConverter",
"@apps/YoutubeSummarizer"
]
},
{
"title": "Settings",
"items": [
"@core/Personalization",
"@core/Modules",
"@core/ServerStatus"
]
},
{
"title": "sso",
"items": [
"@core/LocalizationManager"
]
},
{
"title": "",
"items": [
"@core/Documentation",
"@core/AccountSettings"
]
}
]

View File

@@ -2,10 +2,16 @@
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"lib": [
"ES2020",
"DOM",
"DOM.Iterable"
],
"module": "ESNext",
"skipLibCheck": true,
"types": ["node"],
"types": [
"node"
],
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
@@ -19,19 +25,38 @@
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"paths": {
"@components/*": ["./src/components/*"],
"@providers/*": ["./src/core/providers/*"],
"@hooks/*": ["./src/core/hooks/*"],
"@interfaces/*": ["./src/core/interfaces/*"],
"@utils/*": ["./src/core/utils/*"],
"@apps/*": ["./src/apps/*"],
"@security/*": ["./src/core/security/*"]
"@components/*": [
"./src/components/*"
],
"@providers/*": [
"./src/core/providers/*"
],
"@hooks/*": [
"./src/core/hooks/*"
],
"@interfaces/*": [
"./src/core/interfaces/*"
],
"@utils/*": [
"./src/core/utils/*"
],
"@apps/*": [
"./src/apps/*"
],
"@security/*": [
"./src/core/security/*"
],
"@core/*": [
"./src/core/*"
],
}
},
"include": ["./src/**/*"],
"include": [
"./src/**/*"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
}

View File

@@ -10,6 +10,17 @@ const ReactCompilerConfig = {
}
}
export const alias = {
'@components': path.resolve(__dirname, './src/components'),
'@providers': path.resolve(__dirname, './src/core/providers'),
'@hooks': path.resolve(__dirname, './src/core/hooks'),
'@interfaces': path.resolve(__dirname, './src/core/interfaces'),
'@utils': path.resolve(__dirname, './src/core/utils'),
'@apps': path.resolve(__dirname, './src/apps'),
'@security': path.resolve(__dirname, './src/core/security'),
'@core': path.resolve(__dirname, './src/core')
}
export default defineConfig({
envDir: path.resolve(__dirname, './env'),
plugins: [
@@ -30,15 +41,7 @@ export default defineConfig({
}
},
resolve: {
alias: {
'@components': path.resolve(__dirname, './src/components'),
'@providers': path.resolve(__dirname, './src/core/providers'),
'@hooks': path.resolve(__dirname, './src/core/hooks'),
'@interfaces': path.resolve(__dirname, './src/core/interfaces'),
'@utils': path.resolve(__dirname, './src/core/utils'),
'@apps': path.resolve(__dirname, './src/apps'),
'@security': path.resolve(__dirname, './src/core/security')
}
alias
},
build: {
target: 'esnext',