refactor: accept services prop in PatchTestsManagement and ServicesManagement
Add optional services prop so the page can pass pre-fetched data, avoiding duplicate API calls. Fall back to self-fetching when prop is not provided. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -23,6 +23,12 @@
|
||||
service_ids: string[];
|
||||
};
|
||||
|
||||
interface Props {
|
||||
services?: Service[];
|
||||
}
|
||||
|
||||
let { services: servicesProp }: Props = $props();
|
||||
|
||||
let patchTests = $state<PatchTest[]>([]);
|
||||
let availableServices = $state<Service[]>([]);
|
||||
let loading = $state(true);
|
||||
@@ -99,26 +105,30 @@
|
||||
async function fetchData() {
|
||||
loading = true;
|
||||
try {
|
||||
const [ptRes, svcRes] = await Promise.all([
|
||||
fetch('/api/admin/patch-tests', {
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
}),
|
||||
fetch('/api/admin/services', {
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
})
|
||||
]);
|
||||
const ptRes = await fetch('/api/admin/patch-tests', {
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
});
|
||||
|
||||
if (ptRes.ok && svcRes.ok) {
|
||||
if (ptRes.ok) {
|
||||
patchTests = await ptRes.json();
|
||||
const svcData = await svcRes.json();
|
||||
const uniqueSvc = new SvelteMap<string, Service>();
|
||||
svcData.forEach((s: Service) => {
|
||||
if (s.id) uniqueSvc.set(s.id, s);
|
||||
});
|
||||
availableServices = Array.from(uniqueSvc.values());
|
||||
} else {
|
||||
toast.error('Failed to load patch test data');
|
||||
}
|
||||
|
||||
// Only fetch services if not provided via prop
|
||||
if (!servicesProp) {
|
||||
const svcRes = await fetch('/api/admin/services', {
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
});
|
||||
if (svcRes.ok) {
|
||||
const svcData = await svcRes.json();
|
||||
const uniqueSvc = new SvelteMap<string, Service>();
|
||||
svcData.forEach((s: Service) => {
|
||||
if (s.id) uniqueSvc.set(s.id, s);
|
||||
});
|
||||
availableServices = Array.from(uniqueSvc.values());
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error('Network error loading data');
|
||||
@@ -241,6 +251,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Reactively update availableServices when the parent provides services via prop
|
||||
$effect(() => {
|
||||
if (servicesProp !== undefined) {
|
||||
availableServices = servicesProp;
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
fetchData();
|
||||
});
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
created_by?: string;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
services?: Service[];
|
||||
onRefresh?: () => Promise<void>;
|
||||
}
|
||||
|
||||
let { services: servicesProp, onRefresh }: Props = $props();
|
||||
|
||||
const durationOptions = Array.from({ length: 32 }, (_, i) => (i + 1) * 15);
|
||||
|
||||
let services = $state<Service[]>([]);
|
||||
@@ -139,6 +146,12 @@
|
||||
|
||||
// =============== API Functions ===============
|
||||
async function fetchServices() {
|
||||
// If the parent provides services via prop, delegate refresh to parent
|
||||
if (servicesProp && onRefresh) {
|
||||
await onRefresh();
|
||||
return;
|
||||
}
|
||||
|
||||
servicesLoading = true;
|
||||
try {
|
||||
const response = await fetch('/api/admin/services', {
|
||||
@@ -306,8 +319,18 @@
|
||||
}
|
||||
|
||||
// =============== Lifecycle ===============
|
||||
// Single effect: sync from prop when provided, self-fetch when not.
|
||||
// Combined into one effect to prevent the reactive loop where
|
||||
// fetchServices() → onRefresh() → parent updates → servicesProp changes → effect re-runs.
|
||||
$effect(() => {
|
||||
fetchServices();
|
||||
if (servicesProp !== undefined) {
|
||||
if (servicesProp.length > 0) {
|
||||
services = servicesProp;
|
||||
}
|
||||
servicesLoading = false;
|
||||
} else {
|
||||
fetchServices();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -570,7 +593,7 @@
|
||||
id="service-duration"
|
||||
bind:value={newService.duration_minutes}
|
||||
onblur={validateDurationField}
|
||||
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none {serviceErrors.duration_minutes
|
||||
class="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-xs ring-offset-background transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 {serviceErrors.duration_minutes
|
||||
? 'border-red-500'
|
||||
: ''}"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user