Skip to content

Commit 71dc504

Browse files
committed
feat: implement pet archiving and unarchiving functionality in PetPanel and pet store
1 parent 243305d commit 71dc504

File tree

4 files changed

+72
-10
lines changed

4 files changed

+72
-10
lines changed

src/lib/components/panels/PetPanel.svelte

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import type { PetPanelData } from '$lib/types/Pet.js';
66
77
let pets: PetPanelData[] = [];
8+
// Derived lists
9+
$: activePets = pets.filter((p) => !p.archived);
10+
$: archivedPets = pets.filter((p) => p.archived);
811
let selectedPetId: string | null = null;
912
let showCreateForm = false;
1013
let imageInput: HTMLInputElement;
@@ -139,6 +142,14 @@
139142
}
140143
}
141144
145+
// Keyboard activate handler for elements with role="button"
146+
function handleActivate(e: KeyboardEvent, action: () => void) {
147+
if (e.key === 'Enter' || e.key === ' ') {
148+
e.preventDefault();
149+
action();
150+
}
151+
}
152+
142153
function validateForm() {
143154
formErrors = {};
144155
@@ -197,12 +208,16 @@
197208
selectedPetHelpers.select(petId);
198209
}
199210
200-
function handleActivate(e: KeyboardEvent, action: () => void) {
201-
if (e.key === 'Enter' || e.key === ' ') {
202-
e.preventDefault();
203-
action();
204-
}
205-
}
211+
function archivePet(petId: string) {
212+
petHelpers.archive(petId);
213+
if (selectedPetId === petId) {
214+
selectedPetHelpers.clear();
215+
}
216+
}
217+
218+
function unarchivePet(petId: string) {
219+
petHelpers.unarchive(petId);
220+
}
206221
</script>
207222

208223
<div class="pet-panel h-full" style="background: var(--petalytics-bg);">
@@ -338,16 +353,41 @@
338353
<span class="ml-2" style="color: var(--petalytics-gold);">active_pets</span>
339354
</div>
340355

341-
{#if pets.length === 0}
356+
{#if activePets.length === 0}
342357
<div class="px-2 py-4" style="color: var(--petalytics-subtle);">no pets yet — use add_pet to create one</div>
343358
{:else}
344-
{#each pets as pet}
359+
{#each activePets as pet}
345360
<div class="cli-row px-2 py-1" role="button" tabindex="0" data-selected={selectedPetId === pet.id} onclick={() => selectPet(pet.id)} onkeydown={(e) => handleActivate(e, () => selectPet(pet.id))}>
361+
<span class="label" style="color: var(--petalytics-text);">{pet.name}</span>
362+
<span class="value" style="color: var(--petalytics-subtle);">
363+
{pet.species || 'pet'} | {pet.breed || ''} | {pet.age}{pet.ageUnit === 'months' ? 'm' : pet.ageUnit === 'weeks' ? 'w' : 'y'}
364+
</span>
365+
</div>
366+
<div class="px-2 pb-2 flex justify-end">
367+
<button class="arrow-btn" onclick={() => archivePet(pet.id)}>archive</button>
368+
</div>
369+
{/each}
370+
{/if}
371+
372+
<!-- Archived list -->
373+
<div class="my-3"><div class="border-t" style="border-color: var(--petalytics-border);"></div></div>
374+
<div class="cli-row px-2 py-1">
375+
<span style="color: var(--petalytics-subtle);">#</span>
376+
<span class="ml-2" style="color: var(--petalytics-gold);">archived_pets</span>
377+
</div>
378+
{#if archivedPets.length === 0}
379+
<div class="px-2 py-2" style="color: var(--petalytics-subtle);">none</div>
380+
{:else}
381+
{#each archivedPets as pet}
382+
<div class="cli-row px-2 py-1">
346383
<span class="label" style="color: var(--petalytics-text);">{pet.name}</span>
347384
<span class="value" style="color: var(--petalytics-subtle);">
348385
{pet.species || 'pet'} | {pet.breed || ''} | {pet.age}{pet.ageUnit === 'months' ? 'm' : pet.ageUnit === 'weeks' ? 'w' : 'y'}
349386
</span>
350387
</div>
388+
<div class="px-2 pb-2 flex justify-end">
389+
<button class="arrow-btn" onclick={() => unarchivePet(pet.id)}>unarchive</button>
390+
</div>
351391
{/each}
352392
{/if}
353393
</div>

src/lib/stores/pets.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ export const petHelpers = {
3636
}
3737
},
3838

39+
// Archive pet
40+
archive(petId: string) {
41+
petStore.update((pets) => {
42+
const updated = pets.map((pet) => (pet.id === petId ? { ...pet, archived: true } : pet));
43+
this.save(updated);
44+
// Clear selection if archived pet was selected
45+
selectedPetStore.update((selectedId) => (selectedId === petId ? null : selectedId));
46+
return updated;
47+
});
48+
},
49+
50+
unarchive(petId: string) {
51+
petStore.update((pets) => {
52+
const updated = pets.map((pet) => (pet.id === petId ? { ...pet, archived: false } : pet));
53+
this.save(updated);
54+
return updated;
55+
});
56+
},
57+
3958
// Save pets to localStorage
4059
save(pets: PetPanelData[]) {
4160
try {

src/lib/types/Pet.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface PetPanelData {
3030
gender: 'male' | 'female' | 'unknown';
3131
size?: 'tiny' | 'small' | 'medium' | 'large' | 'extra_large';
3232
profileImageUrl?: string;
33+
archived?: boolean;
3334
createdAt: string;
3435
journalEntries: PetJournalEntry[];
3536
}

src/lib/utils/ai-analysis.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ export class AIAnalyzer {
2020

2121
async analyzeJournalEntry(pet: PetPanelData, entry: JournalEntry): Promise<AnalysisResult> {
2222
const prompt = this.buildAnalysisPrompt(pet, entry);
23+
const referer = typeof window !== 'undefined' ? window.location.origin : undefined;
2324

2425
try {
2526
const response = await fetch(this.baseUrl, {
2627
method: 'POST',
2728
headers: {
2829
Authorization: `Bearer ${this.apiKey}`,
2930
'Content-Type': 'application/json',
30-
'HTTP-Referer': window.location.origin,
31+
...(referer ? { 'HTTP-Referer': referer } : {}),
3132
'X-Title': 'Petalytics',
3233
},
3334
body: JSON.stringify({
@@ -118,12 +119,13 @@ Consider breed-specific traits, age-related needs, and behavioral patterns. Keep
118119

119120
async testConnection(): Promise<boolean> {
120121
try {
122+
const referer = typeof window !== 'undefined' ? window.location.origin : undefined;
121123
const response = await fetch(this.baseUrl, {
122124
method: 'POST',
123125
headers: {
124126
Authorization: `Bearer ${this.apiKey}`,
125127
'Content-Type': 'application/json',
126-
'HTTP-Referer': window.location.origin,
128+
...(referer ? { 'HTTP-Referer': referer } : {}),
127129
'X-Title': 'Petalytics',
128130
},
129131
body: JSON.stringify({

0 commit comments

Comments
 (0)