Skip to content

Commit

Permalink
chore: copied data from electron
Browse files Browse the repository at this point in the history
  • Loading branch information
stephane-segning committed Jul 24, 2024
1 parent 8eaa773 commit 9341a56
Show file tree
Hide file tree
Showing 27 changed files with 356 additions and 52 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>Lynx Scanner</title>
</head>
<body>
<div id="root"></div>
Expand Down
2 changes: 1 addition & 1 deletion openapi-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const baseDir = process.env.GEN_FOLDER!;

const config: ConfigFile = {
schemaFile: './openapi.yaml',
apiFile: './src/store/emptyApi.ts',
apiFile: './src/store/empty.api.ts',
apiImport: 'emptySplitApi',
hooks: true,
outputFiles: {
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
"react-dom": "^18.2.0",
"react-feather": "^2.0.10",
"react-i18next": "^14.1.1",
"react-qr-code": "^2.0.15",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.0",
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
"redux-toolkit": "^1.1.2",
"tailwindcss": "^3.4.3",
"theme-change": "^2.5.0"
Expand All @@ -41,15 +43,18 @@
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@commitlint/format": "^19.3.0",
"@electron-toolkit/preload": "^3.0.1",
"@eslint/eslintrc": "^3.0.2",
"@rtk-query/codegen-openapi": "^1.2.0",
"@types/i18next-browser-languagedetector": "^3.0.0",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/redux-logger": "^3.0.13",
"@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"@vitejs/plugin-react": "^4.2.1",
"daisyui": "^4.10.5",
"electron-log": "^5.1.7",
"esbuild-runner": "^2.2.2",
"eslint": "8",
"eslint-config-prettier": "^9.1.0",
Expand Down
4 changes: 2 additions & 2 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { JSX } from 'react';
import { RouterProvider } from 'react-router-dom';
import { router } from './router.tsx';
import { FloatingConfig } from './components/floating-config.tsx';
import { Notification } from './components/notification.tsx';

/**
* The main application component.
*/
export function App(): JSX.Element {
return (
<div className="mx-auto max-w-screen-lg">
<FloatingConfig />
<RouterProvider router={router} />
<Notification />
</div>
);
}
16 changes: 16 additions & 0 deletions src/components/config.qr-code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { urlConfigSelector, useAppSelector, useFetchConfigUrl } from '../store';
import { Loading } from 'react-daisyui';
import QRCode from 'react-qr-code';
import { useEffect } from 'react';

export default function ConfigQrCode() {
const getUrl = useFetchConfigUrl();
const url = useAppSelector(urlConfigSelector);
useEffect(() => getUrl(), [getUrl]);
return (
<figure>
{!url && <Loading />}
{url && <QRCode value={url} />}
</figure>
);
}
21 changes: 16 additions & 5 deletions src/components/floating-config.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Button, Divider, Dropdown } from 'react-daisyui';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { Menu } from 'react-feather';
import { BarChart2, Globe, Menu, Settings } from 'react-feather';
import { Link } from 'react-router-dom';

interface ThemeButtonProps {
themeName: 'valantine' | 'light' | 'dark';
Expand All @@ -14,6 +15,7 @@ function ThemeButton({ themeName }: ThemeButtonProps) {
data-set-theme={'lynx-' + themeName}
data-act-class={'lynx-' + themeName}
>
<BarChart2 />
{t('config.' + themeName)}
</button>
);
Expand All @@ -38,7 +40,7 @@ export function FloatingConfig() {
<Menu />
</Button>
</Dropdown.Toggle>
<Dropdown.Menu className="w-52 bg-base-100">
<Dropdown.Menu className="w-52 bg-base-200">
<Dropdown.Item anchor={false}>
<ThemeButton themeName="light" />
</Dropdown.Item>
Expand All @@ -50,14 +52,23 @@ export function FloatingConfig() {
</Dropdown.Item>
<Divider />
<Dropdown.Item anchor={false}>
<button onClick={() => changeLanguageHandler('en')}>English</button>
<button onClick={() => changeLanguageHandler('en')}>
<Globe />
<span>English</span>
</button>
</Dropdown.Item>
<Dropdown.Item anchor={false}>
<button onClick={() => changeLanguageHandler('de')}>Deutsch</button>
<button onClick={() => changeLanguageHandler('de')}>
<Globe />
<span>Deutsch</span>
</button>
</Dropdown.Item>
<Divider />
<Dropdown.Item anchor={false}>
<a href="/config">Config</a>
<Link to="/config">
<Settings />
<span>Config</span>
</Link>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
Expand Down
39 changes: 39 additions & 0 deletions src/components/notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
removeNotification,
selectNotifications,
useAppDispatch,
useAppSelector,
} from '../store';
import { Alert, Button, Toast } from 'react-daisyui';
import { useCallback } from 'react';
import { X } from 'react-feather';

export function Notification() {
const notifications = useAppSelector(selectNotifications);
const dispatch = useAppDispatch();
const remove = useCallback(
(msg: string) => () => {
dispatch(removeNotification(msg));
},
[dispatch]
);
return (
<div className="">
{notifications.map((message, index) => (
<Toast horizontal="start" vertical="bottom" key={index}>
<Alert status="error">
<Button
onClick={remove(message)}
color="ghost"
size="sm"
shape="circle"
>
<X />
</Button>
<span>{message}</span>
</Alert>
</Toast>
))}
</div>
);
}
2 changes: 1 addition & 1 deletion src/components/theme-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { themeChange } from 'theme-change';

export function ThemeWrapper({ children }: PropsWithChildren) {
useEffect(() => {
themeChange(true);
themeChange(false);
}, []);

return children;
Expand Down
8 changes: 8 additions & 0 deletions src/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export async function setupLogging() {
const log = await import('electron-log/renderer');
console.log = log.log;
console.debug = log.debug;
console.error = log.error;
console.warn = log.warn;
console.trace = log.verbose;
}
7 changes: 6 additions & 1 deletion src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { setupLogging } from './logging';
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from './app.tsx';
import * as Sentry from '@sentry/react';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n';

import './index.scss';
import { Provider } from 'react-redux';
import { store } from './store';
import { ThemeWrapper } from './components/theme-wrapper.tsx';
import { isElectron } from './shared/constants.ts';

Sentry.init({
dsn: 'https://9fd06d22381ef360013d83b6b0c8375e@o4507214219313152.ingest.de.sentry.io/4507214225801296',
Expand All @@ -25,6 +26,10 @@ Sentry.init({
replaysOnErrorSampleRate: 1.0,
});

if (isElectron) {
setupLogging();
}

const rootElement = document.getElementById('root') as HTMLElement;
const root = ReactDOM.createRoot(rootElement);
root.render(
Expand Down
31 changes: 21 additions & 10 deletions src/router.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
import { createBrowserRouter, Navigate, Outlet } from 'react-router-dom';
import { FloatingConfig } from './components/floating-config.tsx';

export const router = createBrowserRouter([
{
path: '/scans',
element: (
<div className="p-4">
<div>
<FloatingConfig />
<Outlet />
</div>
),
children: [
{
path: 'add',
lazy: () => import('./screens/scan.screen'),
path: '/scans',
element: (
<div className="p-4">
<Outlet />
</div>
),
children: [
{
path: 'add',
lazy: () => import('./screens/scan.screen'),
},
{
path: '',
lazy: () => import('./screens/scan-list.screen'),
},
],
},
{
path: '',
lazy: () => import('./screens/scan-list.screen'),
path: '/config',
lazy: () => import('./screens/app-config.screen'),
},
],
},
{
path: '/config',
lazy: () => import('./screens/app-config.screen'),
},
{
path: '*',
Component: () => <Navigate to="/config" replace={true} />,
Expand Down
18 changes: 15 additions & 3 deletions src/screens/app-config.screen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { useCallback, useEffect } from 'react';
import React, { lazy, useCallback, useEffect } from 'react';
import { t } from 'i18next';
import { Button, Card } from 'react-daisyui';
import { useNavigate } from 'react-router-dom';
import { isElectron } from '../shared/constants.ts';
import { ArrowRight } from 'react-feather';

const ConfigQrCode = lazy(() => import('../components/config.qr-code'));

const configKey = 'lynx:config';

Expand All @@ -17,6 +21,7 @@ export const Component: React.FC = () => {
const scanConfigAndPersist = useCallback(() => {
console.log('scanConfigAndPersist');
}, []);
const toScans = useCallback(() => navigate('/scans'), [navigate]);

useEffect(() => {
const config = checkConfig();
Expand All @@ -27,12 +32,19 @@ export const Component: React.FC = () => {
return (
<div className="flex justify-center items-center h-[100vh] p-4">
<Card className="max-w-sm border-0 sm:border-2 sm:bg-base-200">
{isElectron && <ConfigQrCode />}
<Card.Body>
<Card.Title>{t('config.page')}</Card.Title>
<p>{t('config.description')}</p>
<Card.Actions>
<Button onClick={scanConfigAndPersist} color="primary">
Scan
{isElectron && (
<Button onClick={scanConfigAndPersist} color="primary">
Scan
</Button>
)}
<Button fullWidth color="primary" onClick={toScans}>
<span>To Scans</span>
<ArrowRight />
</Button>
</Card.Actions>
</Card.Body>
Expand Down
9 changes: 1 addition & 8 deletions src/screens/scan-list.screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ import { Button, Loading } from 'react-daisyui';
import { ScanListDump } from '../components/scan-list.dump.tsx';
import { Plus } from 'react-feather';
import { useNavigate } from 'react-router-dom';
import { ErrorDump } from '../components/error.dump.tsx';

export const Component: React.FC = () => {
const [page, setPage] = useState(0);
const {
data: scans,
error,
isLoading,
} = useGetScansQuery({ page: page, size: 10 });
const { data: scans, isLoading } = useGetScansQuery({ page: page, size: 10 });

const navigate = useNavigate();

Expand All @@ -31,8 +26,6 @@ export const Component: React.FC = () => {

{isLoading && <Loading />}

{error && <ErrorDump error={error} />}

{scans && (
<ScanListDump
page={page}
Expand Down
2 changes: 2 additions & 0 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const isElectron: boolean = window.electron !== undefined;
export const isDev: boolean = import.meta.env.DEV;
1 change: 0 additions & 1 deletion src/store/emptyApi.ts → src/store/empty.api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Or from '@reduxjs/toolkit/query' if not using the auto-generated hooks
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

// initialize an empty api service that we'll inject endpoints into later as needed
Expand Down
10 changes: 10 additions & 0 deletions src/store/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useCallback } from 'react';
import { fetchConfigUrl } from './thunks';
import { useAppDispatch } from './types';

export function useFetchConfigUrl() {
const dispatch = useAppDispatch();
return useCallback(() => {
dispatch(fetchConfigUrl());
}, [dispatch]);
}
24 changes: 6 additions & 18 deletions src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import { setupListeners } from '@reduxjs/toolkit/query';
import { configureStore } from '@reduxjs/toolkit';
import { emptySplitApi } from './emptyApi.ts';

export const store = configureStore({
reducer: {
// Add the generated reducer as a specific top-level slice
[emptySplitApi.reducerPath]: emptySplitApi.reducer,
},
// Adding the api middleware enables caching, invalidation, polling,
// and other useful features of `rtk-query`.
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(emptySplitApi.middleware),
});

// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch);
export * from './empty.api';
export * from './hooks';
export * from './store';
export * from './slices';
export * from './types';
export * from './thunks';
Loading

0 comments on commit 9341a56

Please sign in to comment.