A desktop application built with Electron.js.
- Install the required dependencies:
npm install
- Start the development server:
npm run dev
This will launch both the Vite server for the browser and the Electron server, with live-reloading enabled for changes.
- To create the Windows executable:
It's recommended to run the terminal as an administrator to avoid potential errors.
npm run dist:win
The executable will be generated in the dist
folder:
dist/win-unpacked/innhotel-desktop-client.exe
(Portable version)dist/innhotel-desktop-client Setup 0.0.0.exe
(Windows installer)
For other operating systems, use the following commands:
# For macOS
npm run dist:mac
# For Linux
npm run dist:linux
- Electron.js - Framework for building cross-platform desktop applications
- React - JavaScript library for building user interfaces
- Vite - Build tool and development server
- TypeScript - Type-safe JavaScript
- Tailwind CSS - Utility-first CSS framework
- Shadcn - Design system and component library
The application uses React Router DOM for routing. In App.tsx, the application specifically uses HashRouter
instead of BrowserRouter
to support electron.js desktop functionality.
For public pages like login, registration, or landing pages that don't require the full application chrome:
- Create the page component in
src/pages/
:
const LoginPage = () => {
return (
<div className="flex flex-col items-center justify-center min-h-screen p-4">
<div className="w-full max-w-sm space-y-4">
<div className="text-center space-y-2">
<h1 className="text-2xl font-bold">Welcome Back</h1>
<p className="text-muted-foreground">Enter your credentials to continue</p>
</div>
{/* Form or content */}
<LoginForm onSubmit={handleSubmit} />
</div>
</div>
);
};
export default LoginPage;
- Add the route constant in
src/constants/routes.ts
:
export const ROUTES = {
// ... existing routes
LOGIN: '/login',
} as const;
- Add the route in
src/routes/index.tsx
under theMainLayout
section:
<Route path={ROUTES.HOME} element={<MainLayout><Outlet /></MainLayout>}>
<Route path={ROUTES.LOGIN} element={<LoginPage />} />
</Route>
The MainLayout
:
- Used for authentication and public pages
- Provides a clean, minimal layout without navigation elements
- Centered content with responsive padding
- No sidebar, header, or other app chrome
- Suitable for login, registration, and error pages
To add a new regular page that uses the standard AppLayout
:
- Create the page component in
src/pages/
:
const MyPage = () => {
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-3xl font-bold tracking-tight">Page Title</h2>
<Button onClick={() => navigate(ROUTES.ADD_ITEM)}>
<Plus className="mr-2 h-4 w-4" />
Add New
</Button>
</div>
{/* Page content */}
</div>
);
};
export default MyPage;
- Add the route constant in
src/constants/routes.ts
:
export const ROUTES = {
// ... existing routes
MY_PAGE: '/my-page',
} as const;
- Add the route in
src/routes/index.tsx
under theAppLayout
section:
<Route path={ROUTES.HOME} element={<AppLayout><Outlet /></AppLayout>}>
// ... existing routes
<Route path={ROUTES.MY_PAGE} element={<MyPage />} />
</Route>
For pages that use forms (add/edit), use the FormLayout
which provides consistent styling and structure:
- Create the form component in
src/components/my-feature/MyForm.tsx
:
interface MyFormData {
// form fields
}
interface MyFormProps {
onSubmit: (data: MyFormData) => void;
}
export const MyForm = ({ onSubmit }: MyFormProps) => {
const form = useForm<MyFormData>();
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4 max-w-2xl">
{/* Form fields */}
</form>
</Form>
);
};
- Create the page component in
src/pages/
(Here use theFormLayout
):
const AddMyItem = () => {
const navigate = useNavigate();
const handleSubmit = (data: MyFormData) => {
console.log(data);
navigate(ROUTES.MY_PAGE);
};
return (
<FormLayout
title="Add New Item"
description="Add a new item to the system."
>
<MyForm onSubmit={handleSubmit} />
</FormLayout>
);
};
export default AddMyItem;
- Add the route constant in
src/constants/routes.ts
:
export const ROUTES = {
// ... existing routes
MY_PAGE: '/my-page',
ADD_MY_ITEM: '/my-page/add',
} as const;
- Add the route in
src/routes/index.tsx
:
<Route path={ROUTES.HOME} element={<AppLayout><Outlet /></AppLayout>}>
// ... existing routes
<Route path={ROUTES.MY_PAGE} element={<MyPage />} />
<Route path={ROUTES.ADD_MY_ITEM} element={<AddMyItem />} />
</Route>
-
Regular Pages (AppLayout)
- Use for list views, dashboards, and detail pages
- Include a header with title and action buttons
- Follow the space-y-6 pattern for consistent spacing
- Use Shadcn UI components for consistent styling
-
Form Pages (FormLayout)
- Use for add/edit forms
- Provides consistent form styling and structure
- Include a descriptive title and helpful description
- Forms should be wrapped in max-w-2xl for optimal readability
- Use grid layouts for form fields (grid-cols-2 for side-by-side fields)
To add navigation to new pages:
- For main navigation, add to
SidebarNav.tsx
:
const mainItems = [
// ... existing items
{ to: ROUTES.MY_PAGE, label: "My Items", icon: MyIcon },
];
- For quick actions, add to
QuickActions.tsx
:
<DropdownMenuItem onClick={() => navigate(ROUTES.ADD_MY_ITEM)}>
<Plus className="mr-2 h-4 w-4" />
Add New Item
</DropdownMenuItem>