App.tsx
1 import { Refine } from "@refinedev/core"; 2 import { RefineKbar, RefineKbarProvider } from "@refinedev/kbar"; 3 import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; 4 5 import { ErrorComponent } from "@refinedev/antd"; 6 import "@refinedev/antd/dist/reset.css"; 7 8 import { 9 FileOutlined, 10 HighlightOutlined, 11 HomeOutlined, 12 QuestionOutlined, 13 TableOutlined, 14 ToolOutlined, 15 UserOutlined, 16 } from "@ant-design/icons"; 17 import loadable from "@loadable/component"; 18 import routerBindings, { DocumentTitleHandler, UnsavedChangesNotifier } from "@refinedev/react-router"; 19 import { ConfigProvider } from "antd"; 20 import { Locale } from "antd/es/locale"; 21 import { useEffect, useState } from "react"; 22 import { useTranslation } from "react-i18next"; 23 import { BrowserRouter, Outlet, Route, Routes } from "react-router"; 24 import dataProvider from "./components/dataProvider"; 25 import { Favicon } from "./components/favicon"; 26 import { SpoolmanLayout } from "./components/layout"; 27 import liveProvider from "./components/liveProvider"; 28 import SpoolmanNotificationProvider from "./components/notificationProvider"; 29 import { ColorModeContextProvider } from "./contexts/color-mode"; 30 import { languages } from "./i18n"; 31 import { getAPIURL, getBasePath } from "./utils/url"; 32 33 interface ResourcePageProps { 34 resource: "spools" | "filaments" | "vendors"; 35 page: "list" | "create" | "edit" | "show"; 36 mode?: "create" | "clone"; 37 } 38 39 const LoadableResourcePage = loadable( 40 (props: ResourcePageProps) => import(`./pages/${props.resource}/${props.page}.tsx`), 41 { 42 fallback: <div>Page is Loading...</div>, 43 cacheKey: (props: ResourcePageProps) => `${props.resource}-${props.page}-${props.mode ?? ""}`, 44 }, 45 ); 46 47 interface LoadablePageProps { 48 name: string; 49 } 50 51 const LoadablePage = loadable((props: LoadablePageProps) => import(`./pages/${props.name}/index.tsx`), { 52 fallback: <div>Page is Loading...</div>, 53 cacheKey: (props: LoadablePageProps) => `page-${props.name}`, 54 }); 55 56 function App() { 57 const { t, i18n } = useTranslation(); 58 59 const i18nProvider = { 60 translate: (key: string, params?: never) => t(key, params), 61 changeLocale: (lang: string) => i18n.changeLanguage(lang), 62 getLocale: () => i18n.language, 63 }; 64 65 // Fetch the antd locale using dynamic imports 66 const [antdLocale, setAntdLocale] = useState<Locale | undefined>(); 67 useEffect(() => { 68 const fetchLocale = async () => { 69 const locale = await import( 70 `./../node_modules/antd/es/locale/${languages[i18n.language].fullCode.replace("-", "_")}.js` 71 ); 72 setAntdLocale(locale.default); 73 }; 74 fetchLocale().catch(console.error); 75 }, [i18n.language]); 76 77 if (!import.meta.env.VITE_APIURL) { 78 return ( 79 <> 80 <h1>Missing API URL</h1> 81 <p> 82 App was built without an API URL. Please set the VITE_APIURL environment variable to the URL of your Spoolman 83 API. 84 </p> 85 </> 86 ); 87 } 88 89 return ( 90 <BrowserRouter basename={getBasePath() + "/"}> 91 <RefineKbarProvider> 92 <ColorModeContextProvider> 93 <ConfigProvider locale={antdLocale}> 94 <Refine 95 dataProvider={dataProvider(getAPIURL())} 96 notificationProvider={SpoolmanNotificationProvider} 97 i18nProvider={i18nProvider} 98 routerProvider={routerBindings} 99 liveProvider={liveProvider(getAPIURL())} 100 resources={[ 101 { 102 name: "home", 103 list: "/", 104 meta: { 105 canDelete: false, 106 icon: <HomeOutlined />, 107 }, 108 }, 109 { 110 name: "spool", 111 list: "/spool", 112 create: "/spool/create", 113 clone: "/spool/clone/:id", 114 edit: "/spool/edit/:id", 115 show: "/spool/show/:id", 116 meta: { 117 canDelete: true, 118 icon: <FileOutlined />, 119 }, 120 }, 121 { 122 name: "filament", 123 list: "/filament", 124 create: "/filament/create", 125 clone: "/filament/clone/:id", 126 edit: "/filament/edit/:id", 127 show: "/filament/show/:id", 128 meta: { 129 canDelete: true, 130 icon: <HighlightOutlined />, 131 }, 132 }, 133 { 134 name: "vendor", 135 list: "/vendor", 136 create: "/vendor/create", 137 clone: "/vendor/clone/:id", 138 edit: "/vendor/edit/:id", 139 show: "/vendor/show/:id", 140 meta: { 141 canDelete: true, 142 icon: <UserOutlined />, 143 }, 144 }, 145 { 146 name: "locations", 147 list: "/locations", 148 meta: { 149 canDelete: false, 150 icon: <TableOutlined />, 151 }, 152 }, 153 { 154 name: "settings", 155 list: "/settings", 156 meta: { 157 canDelete: false, 158 icon: <ToolOutlined />, 159 }, 160 }, 161 { 162 name: "help", 163 list: "/help", 164 meta: { 165 canDelete: false, 166 icon: <QuestionOutlined />, 167 }, 168 }, 169 ]} 170 options={{ 171 syncWithLocation: true, 172 warnWhenUnsavedChanges: true, 173 disableTelemetry: true, 174 }} 175 > 176 <Routes> 177 <Route 178 element={ 179 <SpoolmanLayout> 180 <Outlet /> 181 </SpoolmanLayout> 182 } 183 > 184 <Route index element={<LoadablePage name="home" />} /> 185 <Route path="/spool"> 186 <Route index element={<LoadableResourcePage resource="spools" page="list" />} /> 187 <Route 188 path="create" 189 element={<LoadableResourcePage resource="spools" page="create" mode="create" />} 190 /> 191 <Route 192 path="clone/:id" 193 element={<LoadableResourcePage resource="spools" page="create" mode="clone" />} 194 /> 195 <Route path="edit/:id" element={<LoadableResourcePage resource="spools" page="edit" />} /> 196 <Route path="show/:id" element={<LoadableResourcePage resource="spools" page="show" />} /> 197 <Route path="print" element={<LoadablePage name="printing" />} /> 198 </Route> 199 <Route path="/filament"> 200 <Route index element={<LoadableResourcePage resource="filaments" page="list" />} /> 201 <Route 202 path="create" 203 element={<LoadableResourcePage resource="filaments" page="create" mode="create" />} 204 /> 205 <Route 206 path="clone/:id" 207 element={<LoadableResourcePage resource="filaments" page="create" mode="clone" />} 208 /> 209 <Route path="edit/:id" element={<LoadableResourcePage resource="filaments" page="edit" />} /> 210 <Route path="show/:id" element={<LoadableResourcePage resource="filaments" page="show" />} /> 211 </Route> 212 <Route path="/vendor"> 213 <Route index element={<LoadableResourcePage resource="vendors" page="list" />} /> 214 <Route 215 path="create" 216 element={<LoadableResourcePage resource="vendors" page="create" mode="create" />} 217 /> 218 <Route 219 path="clone/:id" 220 element={<LoadableResourcePage resource="vendors" page="create" mode="clone" />} 221 /> 222 <Route path="edit/:id" element={<LoadableResourcePage resource="vendors" page="edit" />} /> 223 <Route path="show/:id" element={<LoadableResourcePage resource="vendors" page="show" />} /> 224 </Route> 225 <Route path="/settings/*" element={<LoadablePage name="settings" />} /> 226 <Route path="/help" element={<LoadablePage name="help" />} /> 227 <Route path="/locations" element={<LoadablePage name="locations" />} /> 228 <Route path="*" element={<ErrorComponent />} /> 229 </Route> 230 </Routes> 231 232 <RefineKbar /> 233 <UnsavedChangesNotifier /> 234 <DocumentTitleHandler /> 235 <ReactQueryDevtools /> 236 <Favicon url={getBasePath() + "/favicon.svg"} /> 237 </Refine> 238 </ConfigProvider> 239 </ColorModeContextProvider> 240 </RefineKbarProvider> 241 </BrowserRouter> 242 ); 243 } 244 245 export default App;