fix(config): phase 7 follow-up — fix remaining /ims/ occurrences in sw.js, notifications, components

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 22:32:11 +08:00
co-authored by Claude Sonnet 4.6
parent 9d047e168f
commit 0389d6091a
12 changed files with 21 additions and 21 deletions
+2 -2
View File
@@ -27,7 +27,7 @@ export function SiteZoneManager({ sites }: Props) {
const post = async (payload: Record<string, unknown>) => { const post = async (payload: Record<string, unknown>) => {
setBusy(true) setBusy(true)
setError(null) setError(null)
const res = await fetch('/ims/api/admin/sites', { const res = await fetch('/api/admin/sites', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload), body: JSON.stringify(payload),
@@ -46,7 +46,7 @@ export function SiteZoneManager({ sites }: Props) {
const id = payload.id as string const id = payload.id as string
setBusyId(id) setBusyId(id)
setError(null) setError(null)
const res = await fetch('/ims/api/admin/sites', { const res = await fetch('/api/admin/sites', {
method, method,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload), body: JSON.stringify(payload),
+2 -2
View File
@@ -28,7 +28,7 @@ export function TruckManager({ trucks }: Props) {
setSubmitting(true) setSubmitting(true)
setError(null) setError(null)
try { try {
const res = await fetch('/ims/api/admin/trucks', { const res = await fetch('/api/admin/trucks', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ truck_no: no, carrier: carrier.trim() || null }), body: JSON.stringify({ truck_no: no, carrier: carrier.trim() || null }),
@@ -53,7 +53,7 @@ export function TruckManager({ trucks }: Props) {
setBusyId(id) setBusyId(id)
setError(null) setError(null)
try { try {
const res = await fetch('/ims/api/admin/trucks', { const res = await fetch('/api/admin/trucks', {
method, method,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload), body: JSON.stringify(payload),
+2 -2
View File
@@ -34,7 +34,7 @@ export function UserManager({ users, sites }: Props) {
const patchUser = async (id: string, update: Record<string, unknown>) => { const patchUser = async (id: string, update: Record<string, unknown>) => {
setBusyId(id) setBusyId(id)
setError(null) setError(null)
const res = await fetch('/ims/api/admin/users', { const res = await fetch('/api/admin/users', {
method: 'PATCH', method: 'PATCH',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, ...update }), body: JSON.stringify({ id, ...update }),
@@ -66,7 +66,7 @@ export function UserManager({ users, sites }: Props) {
e.preventDefault() e.preventDefault()
setSubmitting(true) setSubmitting(true)
setError(null) setError(null)
const res = await fetch('/ims/api/admin/users', { const res = await fetch('/api/admin/users', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
+2 -2
View File
@@ -26,7 +26,7 @@ export function CapaForm({ incidentId }: Props) {
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
useEffect(() => { useEffect(() => {
fetch('/ims/api/users') fetch('/api/users')
.then(r => r.json()) .then(r => r.json())
.then(data => { if (Array.isArray(data)) setUsers(data) }) .then(data => { if (Array.isArray(data)) setUsers(data) })
.catch(() => {}) .catch(() => {})
@@ -46,7 +46,7 @@ export function CapaForm({ incidentId }: Props) {
} }
setSaving(true) setSaving(true)
setError(null) setError(null)
const res = await fetch('/ims/api/capa', { const res = await fetch('/api/capa', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
+1 -1
View File
@@ -26,7 +26,7 @@ export function RiskFlagsPanel() {
setLoading(true) setLoading(true)
setError(null) setError(null)
try { try {
const res = await fetch('/ims/api/dashboard/ai/risk-flags', { method: 'POST' }) const res = await fetch('/api/dashboard/ai/risk-flags', { method: 'POST' })
if (!res.ok) { if (!res.ok) {
const data = await res.json().catch(() => ({})) const data = await res.json().catch(() => ({}))
setError(data.error ?? 'Analysis failed') setError(data.error ?? 'Analysis failed')
+1 -1
View File
@@ -30,7 +30,7 @@ export function OfflineSync() {
if (report.type_details) fd.append('type_details', JSON.stringify(report.type_details)) if (report.type_details) fd.append('type_details', JSON.stringify(report.type_details))
try { try {
const res = await fetch('/ims/api/incidents', { method: 'POST', body: fd }) const res = await fetch('/api/incidents', { method: 'POST', body: fd })
if (res.ok && report.id != null) { if (res.ok && report.id != null) {
await removePendingReport(report.id) await removePendingReport(report.id)
} }
+2 -2
View File
@@ -134,7 +134,7 @@ export function ReportForm({ zoneToken, trucks, initialTruckId }: Props) {
if (!overrideQuality) { if (!overrideQuality) {
try { try {
const qcRes = await fetch('/ims/api/incidents/ai/quality-check', { const qcRes = await fetch('/api/incidents/ai/quality-check', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({
@@ -176,7 +176,7 @@ export function ReportForm({ zoneToken, trucks, initialTruckId }: Props) {
if (form.truck_id) fd.append('truck_id', form.truck_id) if (form.truck_id) fd.append('truck_id', form.truck_id)
files.forEach(f => fd.append('files', f)) files.forEach(f => fd.append('files', f))
const res = await fetch('/ims/api/incidents', { method: 'POST', body: fd }) const res = await fetch('/api/incidents', { method: 'POST', body: fd })
// Parse JSON separately so a non-JSON response (HTML error page) surfaces the status code // Parse JSON separately so a non-JSON response (HTML error page) surfaces the status code
let data: Record<string, unknown> = {} let data: Record<string, unknown> = {}
+2 -2
View File
@@ -20,7 +20,7 @@ export function NotificationBell() {
const panelRef = useRef<HTMLDivElement>(null) const panelRef = useRef<HTMLDivElement>(null)
const load = useCallback(() => { const load = useCallback(() => {
fetch('/ims/api/notifications') fetch('/api/notifications')
.then(r => (r.ok ? r.json() : Promise.reject())) .then(r => (r.ok ? r.json() : Promise.reject()))
.then((data: { notifications: Notification[]; unread: number }) => { .then((data: { notifications: Notification[]; unread: number }) => {
setNotifications(data.notifications) setNotifications(data.notifications)
@@ -45,7 +45,7 @@ export function NotificationBell() {
}, [open]) }, [open])
const markAllRead = () => { const markAllRead = () => {
fetch('/ims/api/notifications', { fetch('/api/notifications', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ all: true }), body: JSON.stringify({ all: true }),
+1 -1
View File
@@ -25,7 +25,7 @@ export function ApiKeyForm({ settings }: Props) {
setSaving(s => ({ ...s, [key]: true })) setSaving(s => ({ ...s, [key]: true }))
setResults(r => ({ ...r, [key]: undefined as never })) setResults(r => ({ ...r, [key]: undefined as never }))
try { try {
const res = await fetch('/ims/api/settings', { const res = await fetch('/api/settings', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key, value: values[key] }), body: JSON.stringify({ key, value: values[key] }),
+1 -1
View File
@@ -79,7 +79,7 @@ export async function escalateOverdueCapa(): Promise<{ notified: number }> {
if (!ownerEmail) continue if (!ownerEmail) continue
const incidentRef = capa.incidentRef ?? capa.incidentId const incidentRef = capa.incidentRef ?? capa.incidentId
const capaUrl = `${siteUrl}/ims/hse/capa/${capa.id}` const capaUrl = `${siteUrl}/hse/capa/${capa.id}`
const subject = THRESHOLD_SUBJECT[threshold] const subject = THRESHOLD_SUBJECT[threshold]
const html = ` const html = `
<p>Hi ${ownerName},</p> <p>Hi ${ownerName},</p>
+1 -1
View File
@@ -85,7 +85,7 @@ export async function sendEffectivenessRecheckNotifications(): Promise<{ notifie
const incidentRef = capa.incidentRef ?? capa.incidentId const incidentRef = capa.incidentRef ?? capa.incidentId
const roundLabel = getRoundLabel(round) const roundLabel = getRoundLabel(round)
const capaDesc = capa.description const capaDesc = capa.description
const capaUrl = `${siteUrl}/ims/hse/capa/${capa.id}` const capaUrl = `${siteUrl}/hse/capa/${capa.id}`
const subject = `[IMS] ${roundLabel} effectiveness check — ${incidentRef}` const subject = `[IMS] ${roundLabel} effectiveness check — ${incidentRef}`
const html = ` const html = `
+4 -4
View File
@@ -16,20 +16,20 @@ self.addEventListener('activate', event => {
self.addEventListener('fetch', event => { self.addEventListener('fetch', event => {
const url = new URL(event.request.url) const url = new URL(event.request.url)
// Only handle same-origin GET requests under /ims/ // Only handle same-origin GET requests
if ( if (
event.request.method !== 'GET' || event.request.method !== 'GET' ||
url.origin !== self.location.origin || url.origin !== self.location.origin ||
!url.pathname.startsWith('/ims/') !url.pathname.startsWith('/')
) { ) {
return return
} }
// Skip API routes — always go to network // Skip API routes — always go to network
if (url.pathname.startsWith('/ims/api/')) return if (url.pathname.startsWith('/api/')) return
// Cache-first for immutable Next.js static assets // Cache-first for immutable Next.js static assets
if (url.pathname.startsWith('/ims/_next/static/')) { if (url.pathname.startsWith('/_next/static/')) {
event.respondWith( event.respondWith(
caches.match(event.request).then(cached => { caches.match(event.request).then(cached => {
if (cached) return cached if (cached) return cached