From 8616ba47a2383fd26d2b6ddfb9303a650973f013 Mon Sep 17 00:00:00 2001 From: Randy Hammond Date: Sat, 25 Apr 2026 16:39:58 +0000 Subject: [PATCH] refactor(frontend): group services into services/ws and services/audio (Phase 4) Phase 4 of the directory restructure plan. Pure file moves with import-path updates; no runtime behaviour change. - services/wsClient.ts -> services/ws/client.ts - services/wsClient.test.ts -> services/ws/client.test.ts - services/adminWsClient.ts -> services/ws/adminClient.ts - services/audioPlayer.ts -> services/audio/player.ts - services/beepPlayer.ts -> services/audio/beep.ts services/downloadFilename.ts stays put (not WS, not audio). All @/services/* import sites across components, hooks, and tests have been updated to the new paths. tsc --noEmit clean, 188/188 unit tests pass. --- CHANGELOG.md | 4 ++++ frontend/src/components/scanner/BookmarksPanel.test.tsx | 2 +- frontend/src/components/scanner/BookmarksPanel.tsx | 2 +- frontend/src/components/scanner/ControlToolbar.tsx | 2 +- frontend/src/components/scanner/SearchPanel.tsx | 2 +- frontend/src/hooks/useActiveUnit.ts | 2 +- frontend/src/hooks/useAdminActivity.ts | 2 +- frontend/src/hooks/useAdminLogs.ts | 2 +- frontend/src/hooks/useAdminWebSocket.ts | 2 +- frontend/src/hooks/useAudioPlayer.ts | 4 ++-- frontend/src/hooks/useWebSocket.ts | 2 +- frontend/src/hooks/useWsQuery.ts | 2 +- frontend/src/services/{beepPlayer.ts => audio/beep.ts} | 0 frontend/src/services/{audioPlayer.ts => audio/player.ts} | 2 +- frontend/src/services/{adminWsClient.ts => ws/adminClient.ts} | 0 frontend/src/services/{wsClient.test.ts => ws/client.test.ts} | 2 +- frontend/src/services/{wsClient.ts => ws/client.ts} | 0 17 files changed, 18 insertions(+), 14 deletions(-) rename frontend/src/services/{beepPlayer.ts => audio/beep.ts} (100%) rename frontend/src/services/{audioPlayer.ts => audio/player.ts} (99%) rename frontend/src/services/{adminWsClient.ts => ws/adminClient.ts} (100%) rename frontend/src/services/{wsClient.test.ts => ws/client.test.ts} (99%) rename frontend/src/services/{wsClient.ts => ws/client.ts} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ba03dd..d5ea226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 audio with FFmpeg before storing. Select the codec and bitrate below." to reflect that MP3 and AAC outputs are both supported via the encoding preset. +- Frontend `services/` directory grouped into `services/ws/` (`client.ts`, + `client.test.ts`, `adminClient.ts`) and `services/audio/` (`player.ts`, + `beep.ts`). All `@/services/*` imports across components and hooks have + been updated to the new paths. No runtime behaviour change. ### Fixed diff --git a/frontend/src/components/scanner/BookmarksPanel.test.tsx b/frontend/src/components/scanner/BookmarksPanel.test.tsx index 03b5768..0e4dd93 100644 --- a/frontend/src/components/scanner/BookmarksPanel.test.tsx +++ b/frontend/src/components/scanner/BookmarksPanel.test.tsx @@ -11,7 +11,7 @@ vi.mock("@/app/api", () => ({ useToggleBookmarkMutation: () => mockToggleBookmarkMutation(), })); -vi.mock("@/services/audioPlayer", () => ({ +vi.mock("@/services/audio/player", () => ({ audioPlayer: { play: vi.fn(), }, diff --git a/frontend/src/components/scanner/BookmarksPanel.tsx b/frontend/src/components/scanner/BookmarksPanel.tsx index e5b80d9..e45ab92 100644 --- a/frontend/src/components/scanner/BookmarksPanel.tsx +++ b/frontend/src/components/scanner/BookmarksPanel.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { useGetBookmarkCallsQuery, useToggleBookmarkMutation } from "@/app/api"; import { useAppSelector } from "@/app/store"; import { selectToken } from "@/app/slices/authSlice"; -import { audioPlayer } from "@/services/audioPlayer"; +import { audioPlayer } from "@/services/audio/player"; import { sanitizeDownloadFilename } from "@/services/downloadFilename"; import { ShareCallButton } from "@/components/scanner/ShareCallButton"; import { X, Play, Download, Star, ChevronDown } from "lucide-react"; diff --git a/frontend/src/components/scanner/ControlToolbar.tsx b/frontend/src/components/scanner/ControlToolbar.tsx index 1dc918c..18dad6d 100644 --- a/frontend/src/components/scanner/ControlToolbar.tsx +++ b/frontend/src/components/scanner/ControlToolbar.tsx @@ -13,7 +13,7 @@ import { Search, } from "lucide-react"; import { useCallback } from "react"; -import { playBeep } from "@/services/beepPlayer"; +import { playBeep } from "@/services/audio/beep"; import type { AvoidEntry } from "@/types"; interface ControlToolbarProps { diff --git a/frontend/src/components/scanner/SearchPanel.tsx b/frontend/src/components/scanner/SearchPanel.tsx index cb1aab9..73cb7f9 100644 --- a/frontend/src/components/scanner/SearchPanel.tsx +++ b/frontend/src/components/scanner/SearchPanel.tsx @@ -36,7 +36,7 @@ import { } from "@/app/slices/callsSlice"; import { useGetBookmarkIDsQuery, useToggleBookmarkMutation } from "@/app/api"; import { selectToken } from "@/app/slices/authSlice"; -import { audioPlayer } from "@/services/audioPlayer"; +import { audioPlayer } from "@/services/audio/player"; import { sanitizeDownloadFilename } from "@/services/downloadFilename"; import type { Call } from "@/types"; diff --git a/frontend/src/hooks/useActiveUnit.ts b/frontend/src/hooks/useActiveUnit.ts index 7176f1c..02b7e69 100644 --- a/frontend/src/hooks/useActiveUnit.ts +++ b/frontend/src/hooks/useActiveUnit.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useMemo } from "react"; -import { audioPlayer } from "@/services/audioPlayer"; +import { audioPlayer } from "@/services/audio/player"; interface SourceEntry { pos: number; diff --git a/frontend/src/hooks/useAdminActivity.ts b/frontend/src/hooks/useAdminActivity.ts index f7f8f14..bc645b0 100644 --- a/frontend/src/hooks/useAdminActivity.ts +++ b/frontend/src/hooks/useAdminActivity.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, useRef } from "react"; -import { adminWsClient } from "@/services/adminWsClient"; +import { adminWsClient } from "@/services/ws/adminClient"; import type { ActivityStats, ActivityChartResponse, diff --git a/frontend/src/hooks/useAdminLogs.ts b/frontend/src/hooks/useAdminLogs.ts index 309a7d5..9560cd0 100644 --- a/frontend/src/hooks/useAdminLogs.ts +++ b/frontend/src/hooks/useAdminLogs.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, useRef } from "react"; -import { adminWsClient } from "@/services/adminWsClient"; +import { adminWsClient } from "@/services/ws/adminClient"; import type { AdminLog } from "@/types"; interface LogQueryParams { diff --git a/frontend/src/hooks/useAdminWebSocket.ts b/frontend/src/hooks/useAdminWebSocket.ts index 1982d78..2b43826 100644 --- a/frontend/src/hooks/useAdminWebSocket.ts +++ b/frontend/src/hooks/useAdminWebSocket.ts @@ -1,6 +1,6 @@ import { useEffect, useCallback } from "react"; import { useAppDispatch, useAppSelector } from "@/app/store"; -import { adminWsClient } from "@/services/adminWsClient"; +import { adminWsClient } from "@/services/ws/adminClient"; import { setCredentials, usePostRefreshMutation } from "@/app/slices/authSlice"; import { api } from "@/app/api"; diff --git a/frontend/src/hooks/useAudioPlayer.ts b/frontend/src/hooks/useAudioPlayer.ts index 01e91cd..68f44f0 100644 --- a/frontend/src/hooks/useAudioPlayer.ts +++ b/frontend/src/hooks/useAudioPlayer.ts @@ -1,8 +1,8 @@ import { useEffect, useCallback, useState, useRef } from "react"; import { useAppDispatch, useAppSelector } from "@/app/store"; import { store } from "@/app/store"; -import { audioPlayer } from "@/services/audioPlayer"; -import { wsClient } from "@/services/wsClient"; +import { audioPlayer } from "@/services/audio/player"; +import { wsClient } from "@/services/ws/client"; import { setCurrentCall, clearCurrentCall, diff --git a/frontend/src/hooks/useWebSocket.ts b/frontend/src/hooks/useWebSocket.ts index 678cf22..33f9bb3 100644 --- a/frontend/src/hooks/useWebSocket.ts +++ b/frontend/src/hooks/useWebSocket.ts @@ -1,6 +1,6 @@ import { useEffect, useRef, useCallback } from "react"; import { useAppDispatch, useAppSelector } from "@/app/store"; -import { wsClient } from "@/services/wsClient"; +import { wsClient } from "@/services/ws/client"; import { setCredentials, usePostRefreshMutation } from "@/app/slices/authSlice"; import type { ConnectionStatus } from "@/types"; diff --git a/frontend/src/hooks/useWsQuery.ts b/frontend/src/hooks/useWsQuery.ts index 9035312..2f184d1 100644 --- a/frontend/src/hooks/useWsQuery.ts +++ b/frontend/src/hooks/useWsQuery.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, useRef } from "react"; -import { adminWsClient } from "@/services/adminWsClient"; +import { adminWsClient } from "@/services/ws/adminClient"; // ─── useWsQuery ───────────────────────────────────────────────────────────── diff --git a/frontend/src/services/beepPlayer.ts b/frontend/src/services/audio/beep.ts similarity index 100% rename from frontend/src/services/beepPlayer.ts rename to frontend/src/services/audio/beep.ts diff --git a/frontend/src/services/audioPlayer.ts b/frontend/src/services/audio/player.ts similarity index 99% rename from frontend/src/services/audioPlayer.ts rename to frontend/src/services/audio/player.ts index 6c400e6..85da10c 100644 --- a/frontend/src/services/audioPlayer.ts +++ b/frontend/src/services/audio/player.ts @@ -1,5 +1,5 @@ import type { Call } from "@/types"; -import { bootstrapBeepContext } from "@/services/beepPlayer"; +import { bootstrapBeepContext } from "@/services/audio/beep"; interface QueueItem { call: Call; diff --git a/frontend/src/services/adminWsClient.ts b/frontend/src/services/ws/adminClient.ts similarity index 100% rename from frontend/src/services/adminWsClient.ts rename to frontend/src/services/ws/adminClient.ts diff --git a/frontend/src/services/wsClient.test.ts b/frontend/src/services/ws/client.test.ts similarity index 99% rename from frontend/src/services/wsClient.test.ts rename to frontend/src/services/ws/client.test.ts index b173ff1..d0ea66c 100644 --- a/frontend/src/services/wsClient.test.ts +++ b/frontend/src/services/ws/client.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { wsClient } from "@/services/wsClient"; +import { wsClient } from "@/services/ws/client"; import { configureStore } from "@reduxjs/toolkit"; import { scannerSlice } from "@/app/slices/scannerSlice"; import { authSlice } from "@/app/slices/authSlice"; diff --git a/frontend/src/services/wsClient.ts b/frontend/src/services/ws/client.ts similarity index 100% rename from frontend/src/services/wsClient.ts rename to frontend/src/services/ws/client.ts