Files
2026-07-12 10:17:17 -04:00

99 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ShopProQuote Troubleshooting Patterns
## Pitfall: PocketBase SDK auto-cancellation (`requestKey: null`)
PocketBase JS SDK has auto-cancellation enabled by default. All `create()` and `update()` calls to the same collection share a request key. A second call cancels the first — user sees "auto-cancelled" error.
**Symptom:** Creating a repair order shows "The request was auto-cancelled."
**Root cause:** Rapid double-submit fires two `addDoc` calls. Second POST cancels first via PocketBase's `requestKey` dedup.
**Fix:**
1. Add `{ requestKey: null }` to all PocketBase mutating calls in `pocketbase.js`:
```js
// addDoc
const record = await pb.collection(collName).create(pbData, { requestKey: null });
// updateDoc
const record = await pb.collection(collName).update(docId, pbData, { requestKey: null });
// setDoc (both create and update branches)
return pb.collection(collName).update(records[0].id, pbData, { requestKey: null });
return pb.collection(collName).create(pbData, { requestKey: null });
```
2. Add double-submit guard: disable button on click, re-enable in success/error paths.
```js
const submitBtn = document.getElementById('submit-create-ro');
if (submitBtn && submitBtn.disabled) return;
if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = 'Creating...'; }
```
3. Re-enable on success AND error.
## Pitfall: Auth redirect loop (stale PocketBase token)
**Symptom:** Page constantly refreshes between index.html → dashboard.html → index.html.
**Root cause:** `index.html` line 131: `if(localStorage.getItem('pocketbase_auth')){location.replace('dashboard.html')}`. This is a blind truthy check — ANY string in localStorage (including expired tokens) triggers the redirect. When `dashboard.js` bounces back to `index.html` (invalid auth), the stale token was NEVER cleared, so index.html redirects again. Infinite loop.
**Fix:** Add `localStorage.removeItem('pocketbase_auth')` in ALL auth-fail redirect paths BEFORE navigating away:
- `dashboard.js` onAuthStateChanged → `else` branch
- `repair-orders.js` onAuthStateChanged → `else` branch
- `appointments.js` auth check → `else` branch
```js
} else {
localStorage.removeItem('pocketbase_auth');
window.location.href = 'index.html';
}
```
**Caveat:** If the user sees `login.html` in the redirect, that's browser cache — old JS files referenced `login.html` which no longer exists. All live files redirect to `index.html`. Hard-refresh (Ctrl+Shift+R) or clear site data.
## Pitfall: `ro.status` vs `ro.workStatus` confusion
**Symptom:** Dashboard "Completed Today" shows 0 even when ROs were completed. History filters don't work.
**Root cause:** Repair orders have TWO status fields:
- `ro.status` — customer service status: `'waiter'` or `'drop-off'`
- `ro.workStatus` — work progress: `'diagnosing'`, `'in-progress'`, `'waiting-for-approval'`, `'waiting-for-parts'`, `'waiting-for-pickup'`, `'completed'`
Dashboard.js had 5 instances checking `ro.status === 'completed'` (never true — customer service status is never 'completed'). Must check `ro.workStatus`.
**Also:** For completed filters, use `completedTime` or `financial.completedAt` for the date, NOT `writeupTime`. A RO written last week and completed today should count as completed today.
## Pitfall: DuckDNS auto-detects home IP, not VPS IP
**Symptom:** `grajmedia.duckdns.org` resolves to 162.81.173.34 (home) instead of 51.81.84.34 (VPS).
**Root cause:** DuckDNS update script at `/opt/duckdns/update.sh` uses `&ip=` (empty) which makes DuckDNS use the requesting server's public IP — the home server, not the VPS.
**Fix:** Explicitly set VPS IP:
```bash
echo url="https://www.duckdns.org/update?domains=grajmedia&token=<token>&ip=51.81.84.34" | curl -k -s -o /opt/duckdns/duck.log -K -
```
The `/etc/hosts` entry `127.0.0.1 grajmedia.duckdns.org` is intentional — allows local access without hairpin NAT round-trip through the VPS.
## Pitfall: Completion handler scoping (const in try block)
**Symptom:** Financial modal "Complete" button does nothing after entering all data.
**Root cause:** `roData` declared with `const` inside a `try` block, but referenced outside it:
```js
try {
const roData = getROData(roId); // block-scoped
...
} catch (e) {}
if (roData) { ... } // ReferenceError — roData not defined here
```
The error crashes `handleFinancialCompletion()` silently.
**Fix:** Move declaration outside the try block:
```js
const roData = repairOrders.find(ro => ro.id === roId);
try {
const servicesLines = roData?.services ? ...;
```
## Pattern: Status modal with segmented control
The work status modal uses a 2×3 grid of buttons instead of a dropdown. Each status has a color-coded pill with active state highlighting. Clicking a status immediately applies it (except 'completed' which opens financial modal, and leaving 'waiting-for-parts' which shows a confirmation).