-
Stored clock
+
Stored clock
{formatClock(current)}
-
Incoming clock
+
Incoming clock
{formatClock(incoming)}
diff --git a/apps/web/src/components/icons.tsx b/apps/web/src/components/icons.tsx
index 9274009..75e9068 100644
--- a/apps/web/src/components/icons.tsx
+++ b/apps/web/src/components/icons.tsx
@@ -165,3 +165,37 @@ export function ArrowRightIcon({ className }: IconProps) {
);
}
+
+export function SunIcon({ className }: IconProps) {
+ return (
+
+ );
+}
+
+export function MoonIcon({ className }: IconProps) {
+ return (
+
+ );
+}
+
+export function XIcon({ className }: IconProps) {
+ return (
+
+ );
+}
+
+export function XCircleIcon({ className }: IconProps) {
+ return (
+
+ );
+}
diff --git a/apps/web/src/index.css b/apps/web/src/index.css
index 3ae3532..7cd42da 100644
--- a/apps/web/src/index.css
+++ b/apps/web/src/index.css
@@ -3,7 +3,7 @@
@tailwind utilities;
body {
- background-color: #f8fafc;
+ @apply bg-slate-50 text-slate-900 transition-colors dark:bg-slate-950 dark:text-slate-100;
}
@keyframes fadeIn {
@@ -23,3 +23,14 @@ body {
transform: translateY(4px);
}
}
+
+@keyframes toastIn {
+ from {
+ opacity: 0;
+ transform: translateY(8px) scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
diff --git a/apps/web/src/pages/CheckoutPage.tsx b/apps/web/src/pages/CheckoutPage.tsx
index d949fc4..0cbb18c 100644
--- a/apps/web/src/pages/CheckoutPage.tsx
+++ b/apps/web/src/pages/CheckoutPage.tsx
@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import type { Product } from "@stocksync/core";
import { postCheckout, productsApi, type CheckoutLineItem, type CheckoutResponse } from "../api/client";
import { CartDrawer } from "../components/CartDrawer";
+import { useToast } from "../state/ToastContext";
export interface CheckoutPageProps {
shopId: string;
@@ -20,6 +21,7 @@ export function CheckoutPage({ shopId, counterId }: CheckoutPageProps) {
const [lineItems, setLineItems] = useState
([]);
const [receipt, setReceipt] = useState(undefined);
const [error, setError] = useState(false);
+ const { showToast } = useToast();
useEffect(() => {
productsApi
@@ -51,8 +53,10 @@ export function CheckoutPage({ shopId, counterId }: CheckoutPageProps) {
setReceipt(result);
setLineItems([]);
setError(false);
+ showToast(`Order ${result.order_id} completed — total ₹${result.total_amount}.`, "success");
} catch {
setError(true);
+ showToast("Checkout failed — check the connection and try again.", "error");
}
}
@@ -62,12 +66,15 @@ export function CheckoutPage({ shopId, counterId }: CheckoutPageProps) {
return (
-
Checkout
+
Checkout
- {error &&
Something went wrong. Check the connection and try again.
}
+ {error &&
Something went wrong. Check the connection and try again.
}
{receipt && (
-
+
Order {receipt.order_id} completed — total ₹{receipt.total_amount}.
)}
@@ -79,13 +86,13 @@ export function CheckoutPage({ shopId, counterId }: CheckoutPageProps) {
type="button"
onClick={() => addToCart(product)}
data-testid={`cart-add-${product.product_id}`}
- className="rounded-lg border border-slate-200 bg-white p-3 text-left text-sm hover:bg-slate-50"
+ className="rounded-lg border border-slate-200 bg-white p-3 text-left text-sm hover:bg-slate-50 dark:border-slate-800 dark:bg-slate-900 dark:hover:bg-slate-800"
>
-
{product.name}
-
₹{product.base_price ?? 0}
+
{product.name}
+
₹{product.base_price ?? 0}
))}
- {products.length === 0 &&
No products in the catalog yet.
}
+ {products.length === 0 &&
No products in the catalog yet.
}
@@ -94,7 +101,7 @@ export function CheckoutPage({ shopId, counterId }: CheckoutPageProps) {
type="button"
onClick={() => void handleCheckout()}
disabled={lineItems.length === 0}
- className="mt-4 w-full rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-700 disabled:cursor-not-allowed disabled:opacity-40"
+ className="mt-4 w-full rounded-md bg-slate-900 px-4 py-2 text-sm font-medium text-white hover:bg-slate-700 disabled:cursor-not-allowed disabled:opacity-40 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-300"
>
Complete checkout
diff --git a/apps/web/src/pages/CounterPage.tsx b/apps/web/src/pages/CounterPage.tsx
index fba3f34..3314587 100644
--- a/apps/web/src/pages/CounterPage.tsx
+++ b/apps/web/src/pages/CounterPage.tsx
@@ -12,6 +12,8 @@ import { QueueDrawer } from "../components/QueueDrawer";
import { ConflictReviewPanel } from "../components/ConflictReviewPanel";
import { AuditLogView } from "../components/AuditLogView";
import { BarcodeScanButton } from "../components/BarcodeScanButton";
+import { ItemCardSkeleton } from "../components/Skeleton";
+import { useToast } from "../state/ToastContext";
import { AlertTriangleIcon, BoxIcon, ClockHistoryIcon, ScanIcon } from "../components/icons";
function useQueryParam(name: string, fallback: string): string {
@@ -36,6 +38,7 @@ export function CounterPage() {
const { state, dispatch } = useShopContext();
const { isOnline, toggleOffline } = useConnectivity();
+ const { showToast } = useToast();
const { submitTransaction, replayQueue } = useOfflineQueue(shopId, counterId, isOnline);
useReplayOnReconnect(isOnline, replayQueue);
useWebSocketSync(shopId, counterId, isOnline);
@@ -60,25 +63,21 @@ export function CounterPage() {