Add settings page and temporary home page.

This commit is contained in:
Patrick Fic
2026-01-13 14:47:08 -08:00
parent 319e2e37df
commit 21c132642b
6 changed files with 304 additions and 31 deletions

16
package-lock.json generated
View File

@@ -22,7 +22,6 @@
"winax": "^3.6.2"
},
"devDependencies": {
"@ant-design/v5-patch-for-react-19": "^1.0.3",
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
"@electron-toolkit/eslint-config-ts": "^3.1.0",
"@electron-toolkit/tsconfig": "^2.0.0",
@@ -174,21 +173,6 @@
"react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@ant-design/v5-patch-for-react-19": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@ant-design/v5-patch-for-react-19/-/v5-patch-for-react-19-1.0.3.tgz",
"integrity": "sha512-iWfZuSUl5kuhqLUw7jJXUQFMMkM7XpW7apmKzQBQHU0cpifYW4A79xIBt9YVO5IBajKpPG5UKP87Ft7Yrw1p/w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.x"
},
"peerDependencies": {
"antd": ">=5.22.6",
"react": ">=19.0.0",
"react-dom": ">=19.0.0"
}
},
"node_modules/@apm-js-collab/code-transformer": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/@apm-js-collab/code-transformer/-/code-transformer-0.8.2.tgz",

View File

@@ -35,7 +35,6 @@
"winax": "^3.6.2"
},
"devDependencies": {
"@ant-design/v5-patch-for-react-19": "^1.0.3",
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
"@electron-toolkit/eslint-config-ts": "^3.1.0",
"@electron-toolkit/tsconfig": "^2.0.0",

View File

@@ -1,10 +1,10 @@
import "@ant-design/v5-patch-for-react-19";
import { ConfigProvider, Layout, Space } from "antd";
import { ConfigProvider, Layout } from "antd";
import { FC } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { Provider } from "react-redux";
import { HashRouter, Route, Routes } from "react-router";
import ErrorBoundaryFallback from "./components/ErrorBoundaryFallback/ErrorBoundaryFallback";
import Home from "./components/Home/Home";
import Settings from "./components/Settings/Settings";
import UpdateAvailable from "./components/UpdateAvailable/UpdateAvailable";
import reduxStore from "./redux/redux-store";
@@ -32,7 +32,8 @@ const App: FC = () => {
<Layout.Content style={{ padding: "24px" }}>
<UpdateAvailable />
<Routes>
<Route path="/" element={<Settings />} />
<Route path="/" element={<Home />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Layout.Content>
</Layout>

View File

@@ -0,0 +1,284 @@
// renderer/Home.tsx
import {
Button,
Card,
Col,
Flex,
Row,
Space,
Statistic,
Table,
Tag,
Typography,
theme,
List,
Avatar,
Divider,
} from "antd";
import { FC } from "react";
import { useNavigate } from "react-router";
import {
FileTextOutlined,
CheckCircleOutlined,
ClockCircleOutlined,
SettingOutlined,
EyeOutlined,
RightOutlined,
} from "@ant-design/icons";
const { Title, Text, Paragraph } = Typography;
// Placeholder data for recently scrubbed estimates
const placeholderEstimates = [
{
id: "EST-2026-001",
fileName: "estimate_john_doe.pdf",
scrubbedAt: "2026-01-12T10:30:00",
status: "completed",
itemsProcessed: 24,
},
{
id: "EST-2026-002",
fileName: "estimate_jane_smith.pdf",
scrubbedAt: "2026-01-12T09:15:00",
status: "completed",
itemsProcessed: 18,
},
{
id: "EST-2026-003",
fileName: "estimate_acme_corp.pdf",
scrubbedAt: "2026-01-11T16:45:00",
status: "completed",
itemsProcessed: 32,
},
{
id: "EST-2026-004",
fileName: "estimate_bob_johnson.pdf",
scrubbedAt: "2026-01-11T14:20:00",
status: "completed",
itemsProcessed: 15,
},
{
id: "EST-2026-005",
fileName: "estimate_tech_solutions.pdf",
scrubbedAt: "2026-01-11T11:00:00",
status: "completed",
itemsProcessed: 27,
},
];
const columns = [
{
title: "Estimate",
dataIndex: "id",
key: "id",
responsive: ["md"] as const,
render: (text: string, record: (typeof placeholderEstimates)[0]) => (
<Space orientation="vertical" size={0}>
<Text strong>{text}</Text>
<Text type="secondary" style={{ fontSize: "12px" }}>
{record.fileName}
</Text>
</Space>
),
},
{
title: "File",
dataIndex: "fileName",
key: "fileName",
responsive: ["xs"] as const,
render: (text: string, record: (typeof placeholderEstimates)[0]) => (
<Space orientation="vertical" size={0}>
<Text strong>{record.id}</Text>
<Text type="secondary" style={{ fontSize: "12px" }}>
{text}
</Text>
</Space>
),
},
{
title: "Scrubbed",
dataIndex: "scrubbedAt",
key: "scrubbedAt",
responsive: ["sm"] as const,
render: (text: string) => {
const date = new Date(text);
return (
<Space orientation="vertical" size={0}>
<Text>{date.toLocaleDateString()}</Text>
<Text type="secondary" style={{ fontSize: "12px" }}>
{date.toLocaleTimeString()}
</Text>
</Space>
);
},
},
{
title: "Items",
dataIndex: "itemsProcessed",
key: "itemsProcessed",
responsive: ["lg"] as const,
render: (value: number) => <Text strong>{value}</Text>,
},
{
title: "Status",
dataIndex: "status",
key: "status",
responsive: ["sm"] as const,
render: (status: string) => (
<Tag
color={status === "completed" ? "success" : "processing"}
icon={<CheckCircleOutlined />}
style={{ margin: 0 }}
>
{status === "completed" ? "Done" : "Processing"}
</Tag>
),
},
{
title: "",
key: "action",
width: 100,
render: () => (
<Button type="link" icon={<EyeOutlined />} size="small">
View
</Button>
),
},
];
const Home: FC = () => {
const navigate = useNavigate();
const { token } = theme.useToken();
return (
<div style={{ maxWidth: "1400px", margin: "0 auto" }}>
<Space
direction="vertical"
size="large"
style={{ width: "100%", display: "flex" }}
>
{/* Header */}
<Flex justify="space-between" align="center" wrap="wrap" gap="small">
<Title level={2} style={{ margin: 0 }}>
Dashboard
</Title>
<Button
type="default"
icon={<SettingOutlined />}
onClick={() => navigate("/settings")}
size="large"
>
Settings
</Button>
</Flex>
{/* Stats Cards */}
<Row gutter={[16, 16]}>
<Col xs={24} sm={12} lg={8}>
<Card
bordered={false}
style={{
background: `linear-gradient(135deg, ${token.colorPrimary} 0%, ${token.colorPrimaryHover} 100%)`,
}}
>
<Statistic
title={
<span style={{ color: "rgba(255,255,255,0.85)" }}>
Total Estimates
</span>
}
value={placeholderEstimates.length}
prefix={<FileTextOutlined style={{ color: "#fff" }} />}
valueStyle={{ color: "#fff", fontWeight: 600 }}
/>
</Card>
</Col>
<Col xs={24} sm={12} lg={8}>
<Card
bordered={false}
style={{
background: `linear-gradient(135deg, #52c41a 0%, #73d13d 100%)`,
}}
>
<Statistic
title={
<span style={{ color: "rgba(255,255,255,0.85)" }}>
Items Scrubbed
</span>
}
value={placeholderEstimates.reduce(
(acc, est) => acc + est.itemsProcessed,
0,
)}
prefix={<CheckCircleOutlined style={{ color: "#fff" }} />}
valueStyle={{ color: "#fff", fontWeight: 600 }}
/>
</Card>
</Col>
<Col xs={24} sm={24} lg={8}>
<Card
bordered={false}
style={{
background: `linear-gradient(135deg, #722ed1 0%, #9254de 100%)`,
}}
>
<Statistic
title={
<span style={{ color: "rgba(255,255,255,0.85)" }}>
Last Processed
</span>
}
value={new Date(
placeholderEstimates[0].scrubbedAt,
).toLocaleTimeString()}
prefix={<ClockCircleOutlined style={{ color: "#fff" }} />}
valueStyle={{ color: "#fff", fontWeight: 600 }}
/>
</Card>
</Col>
</Row>
{/* Recent Estimates Card */}
<Card
bordered={false}
title={
<Flex align="center" gap="small">
<FileTextOutlined style={{ fontSize: "20px" }} />
<span>Recently Scrubbed Estimates</span>
</Flex>
}
extra={
<Button
type="primary"
icon={<RightOutlined />}
iconPlacement="end"
onClick={() => alert("View all estimates - coming soon!")}
>
View All
</Button>
}
styles={{
header: {
borderBottom: `2px solid ${token.colorBorderSecondary}`,
},
}}
>
{/* Table view for larger screens */}
<div style={{ display: "block" }}>
<Table
columns={columns}
dataSource={placeholderEstimates}
rowKey="id"
pagination={{ pageSize: 5, showSizeChanger: false }}
scroll={{ x: 800 }}
style={{ overflow: "auto" }}
/>
</div>
</Card>
</Space>
</div>
);
};
export default Home;

View File

@@ -1,26 +1,18 @@
import { useAppSelector } from "@renderer/redux/reduxHooks";
import {
CheckCircleFilled,
ExclamationCircleFilled,
PauseCircleOutlined,
PlayCircleOutlined,
} from "@ant-design/icons";
import { PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons";
import {
selectWatcherError,
selectWatcherStatus,
} from "@renderer/redux/app.slice";
import { useAppSelector } from "@renderer/redux/reduxHooks";
import {
Alert,
Badge,
Button,
Card,
Divider,
Flex,
InputNumber,
Radio,
RadioChangeEvent,
Space,
Switch,
Typography,
} from "antd";
import { FC, useEffect, useState } from "react";

View File

@@ -1,12 +1,25 @@
// renderer/Settings.tsx
import { Space } from "antd";
import { Button, Space } from "antd";
import { ArrowLeftOutlined } from "@ant-design/icons";
import { FC } from "react";
import { useNavigate } from "react-router";
import SettingsConfig from "./Settings.Config";
import SettingsWatcher from "./Settings.Watcher";
const Settings: FC = () => {
const navigate = useNavigate();
return (
<Space orientation="vertical" size="large" style={{ width: "100%" }}>
<Button
type="text"
icon={<ArrowLeftOutlined />}
onClick={() => navigate("/")}
style={{ alignSelf: "flex-start" }}
>
Back
</Button>
<SettingsWatcher />
<SettingsConfig />