commit da3f3bff39f09e753c1c52de0c47a12383cd20dc
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:49:31 2025 +0900
docs: add README files for frontend and backend with setup instructions and commands
commit df71faa0751d1cef3ad6d50d0293fb8f8239d000
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:44:13 2025 +0900
chore: update Vite version and add Vitest configuration
- Updated Vite dependency from rolldown-vite@7.1.12 to ^5.4.11 in package.json.
- Added setup file for Vitest to handle Vite SSR helpers, preventing ReferenceError during unit tests.
- Created a new tsconfig.vitest.json file extending the main tsconfig for Vitest compatibility.
- Added vitest.config.ts to configure Vitest with Node environment and setup files.
commit f3a1710dd0fe12998965992f6b5f8803422087cf
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:37:32 2025 +0900
feat: add testing framework and implement unit tests for API and config
- Added Vitest as a testing framework with scripts for running tests.
- Created unit tests for the `fetchSchedule` and `fetchServerNow` functions in `watchparty.test.ts`.
- Implemented unit tests for configuration functions in `config.test.ts`.
- Added utility functions for parsing time in `time.ts` with corresponding tests in `time.test.ts`.
- Updated API error handling to use `unknown` type for better type safety.
- Refactored `TimeSyncNotice` and `Timer` components to improve performance and error handling.
- Enhanced toast notifications by moving related functions to `toastBus.ts`.
- Improved type definitions across various files for better type safety and clarity.
commit 0d436849fc4a0b87d0c73f4fe14fe1e272d47ad9
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:30:01 2025 +0900
Refactor components to utilize centralized configuration: update TimeSyncNotice and Timer to use config for intervals; enhance error handling and retry logic in ShowsPage.
commit 8dbd4d207a471d05fab8c6f9cd95e3f4f7ec9099
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:22:28 2025 +0900
Refactor API endpoint handling: replace join function with buildApiUrl for cleaner URL construction; update BrowserRouter basename to use config
commit 3e327aa73877034019dffe262580536f4be7c62e
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:18:31 2025 +0900
Refactor configuration management: introduce config.ts for centralized app configuration; update API endpoint handling and logger to use new config
commit 131984d1baf368f94a14a62986eaf028ebbd7c86
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:11:33 2025 +0900
Refactor API types: move ScheduleResponse and ShowItem types to a new types.ts file; update imports in watchparty and Timer components
commit 8faa4661a9ccc0691490a5766f0eb1d97f24b6e5
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 02:05:42 2025 +0900
Refactor API handling: introduce centralized error handling and logging; replace direct fetch calls with apiFetch in Timer, ShowsPage, and hooks
commit ffde7e89fcab6f48c6023afab73e4b2e1122efa5
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 01:52:36 2025 +0900
Add dist directory to .gitignore
commit 128a5be6eaa16bf4db5f7dd832b1d461fa2b835d
Author: Nik Afiq <nik.afiq98@ymail.com>
Date: Sat Dec 6 01:52:28 2025 +0900
Add toast notifications and debug overlay components; refactor Timer and ShowsPage for error handling
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import React from "react";
|
|
import { Link, NavLink, Route, Routes, useLocation } from "react-router-dom";
|
|
import Timer from "./components/Timer";
|
|
import ShowsPage from "./pages/ShowsPage";
|
|
import TimeSyncNotice from "./components/TimeSyncNotice";
|
|
import { ToastViewport } from "./components/Toasts";
|
|
import DebugOverlay from "./components/DebugOverlay";
|
|
import "./index.css";
|
|
|
|
const TIME_SYNC_OFF_THRESHOLD = 100;
|
|
|
|
export default function App() {
|
|
const [open, setOpen] = React.useState(false);
|
|
const loc = useLocation();
|
|
|
|
// close sidebar on route change
|
|
React.useEffect(() => setOpen(false), [loc.pathname]);
|
|
|
|
// ESC to close
|
|
React.useEffect(() => {
|
|
const onKey = (e: KeyboardEvent) => e.key === "Escape" && setOpen(false);
|
|
window.addEventListener("keydown", onKey);
|
|
return () => window.removeEventListener("keydown", onKey);
|
|
}, []);
|
|
|
|
return (
|
|
<div className={`site ${open ? "sidebar-open" : ""}`}>
|
|
{/* Top-left header (outside the card) */}
|
|
<header className="site-header">
|
|
|
|
<button className="burger" aria-label="メニュー" onClick={() => setOpen(v => !v)}>
|
|
<svg className="burger-icon" viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
|
|
<path d="M4 7h16M4 12h16M4 17h16"
|
|
stroke="currentColor" strokeWidth="2"
|
|
strokeLinecap="round" strokeLinejoin="round" fill="none" />
|
|
</svg>
|
|
</button>
|
|
<Link to="/" className="brand">Watch Party</Link>
|
|
</header>
|
|
{/* Time sync banner (checks every 5 min; shows if |skew| > 500ms) */}
|
|
<TimeSyncNotice thresholdMs={TIME_SYNC_OFF_THRESHOLD} lang="ja" />
|
|
|
|
{/* Sidebar (full-height) */}
|
|
<aside className={`sidebar ${open ? "open" : ""}`} aria-hidden={!open}>
|
|
<nav className="sidebar-nav" onClick={() => setOpen(false)}>
|
|
<NavLink end to="/" className="navlink">Timer</NavLink>
|
|
<NavLink to="/shows" className="navlink">Shows</NavLink>
|
|
</nav>
|
|
</aside>
|
|
|
|
{/* Backdrop for overlap mode or to close on click */}
|
|
<button
|
|
className={`backdrop ${open ? "open" : ""}`}
|
|
aria-hidden={!open}
|
|
onClick={() => setOpen(false)}
|
|
tabIndex={-1}
|
|
/>
|
|
|
|
{/* Main content area (card inside) */}
|
|
<main className="site-content">
|
|
<div className="card">
|
|
<Routes>
|
|
<Route path="/" element={<Timer />} />
|
|
<Route path="/shows" element={<ShowsPage />} />
|
|
</Routes>
|
|
|
|
<div className="footer">
|
|
Built by{" "}
|
|
<a href="https://x.com/nik4nao" target="_blank" rel="noopener noreferrer">
|
|
@nik4nao
|
|
</a>{" "}
|
|
— contact for inquiries or requirements.
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<ToastViewport />
|
|
<DebugOverlay />
|
|
</div>
|
|
);
|
|
}
|