Add full PWA support (icons, manifest, service worker, pwa lib and bridge) and introduce install/offline UI. Generate app icons via a new scripts/generate-icons.js and include multiple icon sizes in public/icons; update manifest and layout head meta/preconnect. Revamp global styles (globals.css) with new utilities, animations, spacing for bottom nav, card shadows, skeletons and accessibility tweaks. Polish major screens (login, collections, map, settings) with improved headers, loading states, touch/press feedback, and layout adjustments; add new components (InstallPrompt, OfflineIndicator, PWABridge) and update various components to match new visual/UX patterns. Update Dockerfile to generate icons and use Next.js static export output (/out) for nginx, and bump package setup to support icon generation.
113 lines
No EOL
3.4 KiB
TypeScript
113 lines
No EOL
3.4 KiB
TypeScript
import PocketBase from 'pocketbase';
|
|
import { AppSettings, DEFAULT_SETTINGS, OrderItem, DriverLocation } from './types';
|
|
|
|
const POCKETBASE_URL = process.env.NEXT_PUBLIC_POCKETBASE_URL || 'https://pocketbase-gnqc88suy8fqk6wyryjjdpvl.169.239.180.130.sslip.io';
|
|
|
|
export const pb = new PocketBase(POCKETBASE_URL);
|
|
|
|
// Disable auto-cancellation so React re-renders don't kill in-flight requests
|
|
pb.autoCancellation(false);
|
|
|
|
// Auth helpers
|
|
export const isAuthenticated = () => pb.authStore.isValid;
|
|
|
|
export const getCurrentUser = () => pb.authStore.model;
|
|
|
|
export const logout = () => {
|
|
pb.authStore.clear();
|
|
if (typeof window !== 'undefined') {
|
|
window.location.href = '/login/';
|
|
}
|
|
};
|
|
|
|
export const login = async (email: string, password: string) => {
|
|
return await pb.collection('users').authWithPassword(email, password);
|
|
};
|
|
|
|
// Get assigned collections (order_items assigned to current driver)
|
|
export const getAssignedCollections = async () => {
|
|
const user = getCurrentUser();
|
|
if (!user) return [];
|
|
|
|
const records = await pb.collection('order_items').getFullList({
|
|
filter: `driver = "${user.id}" && (item_status = "assigned" || item_status = "driver_pool")`,
|
|
expand: 'supplier,order,purchase_order',
|
|
sort: 'supplier.suppliername',
|
|
});
|
|
|
|
return records as unknown as OrderItem[];
|
|
};
|
|
|
|
// Update order item status when collected
|
|
export const updateCollectionStatus = async (
|
|
id: string,
|
|
status: string,
|
|
data: { qty_collected?: number; notes?: string; collected_date?: string; problem_type?: string; problem_flag?: boolean }
|
|
) => {
|
|
return await pb.collection('order_items').update(id, {
|
|
item_status: status,
|
|
...data,
|
|
});
|
|
};
|
|
|
|
// Report a problem on an order item
|
|
export const reportProblem = async (
|
|
orderItemId: string,
|
|
problemType: string,
|
|
description: string
|
|
) => {
|
|
return await pb.collection('order_items').update(orderItemId, {
|
|
item_status: 'problem',
|
|
problem_type: problemType,
|
|
problem_flag: true,
|
|
problem_notes: description,
|
|
});
|
|
};
|
|
|
|
// Location tracking - tries to save, fails silently if table doesn't exist
|
|
export const saveDriverLocation = async (location: Omit<DriverLocation, 'id'>) => {
|
|
try {
|
|
return await pb.collection('driver_locations').create(location);
|
|
} catch {
|
|
// Silently fail - table may not exist yet
|
|
}
|
|
};
|
|
|
|
// Get driver's location trail for today (for map polyline)
|
|
export const getDriverTrail = async (driverId: string) => {
|
|
try {
|
|
const today = new Date();
|
|
today.setHours(0, 0, 0, 0);
|
|
const records = await pb.collection('driver_locations').getFullList({
|
|
filter: `driver = "${driverId}" && timestamp >= "${today.toISOString()}"`,
|
|
sort: 'timestamp',
|
|
});
|
|
return records as unknown as DriverLocation[];
|
|
} catch {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
// Settings helpers
|
|
const SETTINGS_KEY = '1driver_settings';
|
|
|
|
export const getSettings = (): AppSettings => {
|
|
if (typeof window === 'undefined') return DEFAULT_SETTINGS;
|
|
const saved = localStorage.getItem(SETTINGS_KEY);
|
|
if (saved) {
|
|
try {
|
|
return { ...DEFAULT_SETTINGS, ...JSON.parse(saved) };
|
|
} catch {
|
|
return DEFAULT_SETTINGS;
|
|
}
|
|
}
|
|
return DEFAULT_SETTINGS;
|
|
};
|
|
|
|
export const saveSettings = (settings: Partial<AppSettings>) => {
|
|
if (typeof window === 'undefined') return;
|
|
const current = getSettings();
|
|
const updated = { ...current, ...settings };
|
|
localStorage.setItem(SETTINGS_KEY, JSON.stringify(updated));
|
|
return updated;
|
|
}; |