11<script lang =" ts" >
2- import pb from ' $lib/pocketbase' ;
3- import { goto } from ' $app/navigation' ;
4-
5- type ViewMode = ' cps' | ' characters' ;
6- let mode = $state <ViewMode >(' cps' );
7- let items = $state <any []>([]);
8- let isLoading = $state (true );
9-
10- async function fetchMyData(currentMode : ViewMode ) {
11- // 安全守卫:如果没有登录,直接跳走
12- if (! pb .authStore .isValid || ! pb .authStore .record ) {
13- goto (' /login' );
14- return ;
15- }
2+ import pb from ' $lib/pocketbase' ;
3+ import { goto } from ' $app/navigation' ;
4+
5+ type ViewMode = ' cps' | ' characters' ;
6+ let mode = $state <ViewMode >(' cps' );
7+ let items = $state <any []>([]);
8+ let isLoading = $state (true );
9+ let deleteModal = $state () as HTMLDialogElement ;
10+ let itemToDelete = $state <null | any >(null );
1611
17- isLoading = true ;
18- const userId = pb .authStore .record .id ;
12+ const handleDelete = (item : any ) => {
13+ itemToDelete = item
14+ deleteModal .showModal ()
15+ };
1916
17+ const confirmDelete = async () => {
2018 try {
21- const collection = currentMode === ' cps' ? ' cps' : ' characters' ;
22- const options = {
23- // 关键点:只获取 owner 是当前用户的记录
24- filter: ` owner = "${userId }" ` ,
25- sort: ' -created' ,
26- expand: currentMode === ' cps' ? ' characters' : ' '
27- };
28-
29- items = await pb .collection (collection ).getFullList (options );
19+ await pb .collection (itemToDelete .collectionName ).delete (itemToDelete .id );
20+ deleteModal .close ();
21+ fetchMyData (mode );
3022 } catch (err ) {
31- console .error (" Fetch error:" , err );
32- } finally {
33- isLoading = false ;
23+ alert (' Delete failed. Please try again.' )
24+ console .error (' Delete error:' , err );
3425 }
3526 }
3627
37- // 监听 mode 变化自动刷新
38- $effect (() => {
39- fetchMyData (mode );
40- });
28+ async function fetchMyData(currentMode : ViewMode ) {
29+ // 安全守卫:如果没有登录,直接跳走
30+ if (! pb .authStore .isValid || ! pb .authStore .record ) {
31+ goto (' /login' );
32+ return ;
33+ }
34+
35+ isLoading = true ;
36+ const userId = pb .authStore .record .id ;
37+
38+ try {
39+ const collection = currentMode === ' cps' ? ' cps' : ' characters' ;
40+ const options = {
41+ // 关键点:只获取 owner 是当前用户的记录
42+ filter: ` owner = "${userId }" ` ,
43+ sort: ' -created' ,
44+ expand: currentMode === ' cps' ? ' characters' : ' '
45+ };
46+
47+ items = await pb .collection (collection ).getFullList (options );
48+ } catch (err ) {
49+ console .error (' Fetch error:' , err );
50+ } finally {
51+ isLoading = false ;
52+ }
53+ }
54+
55+ // 监听 mode 变化自动刷新
56+ $effect (() => {
57+ fetchMyData (mode );
58+ });
4159 </script >
4260
4361<div class =" mx-auto max-w-6xl px-6 py-16" >
44- <div class =" mb-12" >
45- <h1 class =" text-4xl font-bold md:text-5xl" >My Stuff</h1 >
46- <p class =" text-base-content/60 mt-2" >Manage the CPs and Characters you've created.</p >
47-
48- <div role =" tablist" class =" tabs tabs-boxed mt-6 w-fit" >
49- <button
50- role =" tab"
51- class ="tab {mode === ' cps' ? ' tab-active' : ' ' }"
52- onclick ={() => mode = ' cps' }
53- >My CPs</button >
54- <button
55- role =" tab"
56- class ="tab {mode === ' characters' ? ' tab-active' : ' ' }"
57- onclick ={() => mode = ' characters' }
58- >My Characters</button >
59- </div >
60- </div >
61-
62- {#if isLoading }
63- <div class =" flex justify-center py-20" >
64- <span class =" loading loading-spinner loading-lg text-primary" ></span >
65- </div >
66- {:else if items .length === 0 }
67- <div class =" card bg-base-200 py-20 text-center border-2 border-dashed border-base-300" >
68- <div class =" card-body items-center" >
69- <h2 class ="card-title text-2xl opacity-40" >You haven't created any {mode === ' cps' ? ' CP' : ' characters' } yet.</h2 >
70- <div class =" card-actions mt-4" >
71- <a href ="/create" class ="btn btn-primary" >Create Your First {mode === ' cps' ? ' CP' : ' character' }</a >
72- </div >
73- </div >
74- </div >
75- {:else }
76- <div class =" grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3" >
77- {#each items as item }
78- <div class =" card bg-base-100 shadow-xl border border-base-200" >
79- <div class =" card-body p-5" >
80- <h2 class ="card-title" >{item .name }</h2 >
81- <div class =" card-actions justify-end mt-4" >
82- <a href ="/edit/ {mode }/ {item .id }" class =" btn btn-sm btn-ghost" >Edit</a >
83- <a href ="/ {mode }/ {item .id }" class =" btn btn-sm btn-primary" >View</a >
84- </div >
85- </div >
86- </div >
87- {/each }
88- </div >
89- {/if }
90- </div >
62+ <div class =" mb-12" >
63+ <h1 class =" text-4xl font-bold md:text-5xl" >My Stuff</h1 >
64+ <p class =" mt-2 text-base-content/60" >Manage the CPs and Characters you've created.</p >
65+
66+ <div role =" tablist" class =" tabs-boxed mt-6 tabs w-fit" >
67+ <button
68+ role =" tab"
69+ class ="tab {mode === ' cps' ? ' tab-active' : ' ' }"
70+ onclick ={() => (mode = ' cps' )}>My CPs</button
71+ >
72+ <button
73+ role =" tab"
74+ class ="tab {mode === ' characters' ? ' tab-active' : ' ' }"
75+ onclick ={() => (mode = ' characters' )}>My Characters</button
76+ >
77+ </div >
78+ </div >
79+
80+ {#if isLoading }
81+ <div class =" flex justify-center py-20" >
82+ <span class =" loading loading-lg loading-spinner text-primary" ></span >
83+ </div >
84+ {:else if items .length === 0 }
85+ <div class =" card border-2 border-dashed border-base-300 bg-base-200 py-20 text-center" >
86+ <div class =" card-body items-center" >
87+ <h2 class =" card-title text-2xl opacity-40" >
88+ You haven't created any {mode === ' cps' ? ' CP' : ' characters' } yet.
89+ </h2 >
90+ <div class =" mt-4 card-actions" >
91+ <a href =" /create" class =" btn btn-primary"
92+ >Create Your First {mode === ' cps' ? ' CP' : ' character' }</a
93+ >
94+ </div >
95+ </div >
96+ </div >
97+ {:else }
98+ <div class =" grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3" >
99+ {#each items as item }
100+ <div class =" card border border-base-200 bg-base-100 shadow-xl" >
101+ <div class =" card-body p-5" >
102+ <h2 class ="card-title" >{item .name }</h2 >
103+ <div class =" mt-4 card-actions flex justify-end gap-1" >
104+ <button class ="btn w-14 btn-soft btn-sm btn-error" onclick ={() => handleDelete (item )}>
105+ Delete
106+ </button >
107+
108+ <a href ="/edit/ {mode }/ {item .id }" class =" btn w-14 btn-ghost btn-sm" > Edit </a >
109+
110+ <a href ="/ {mode }/ {item .id }" class =" btn w-14 btn-sm btn-primary" > View </a >
111+ </div >
112+ </div >
113+ </div >
114+ {/each }
115+ </div >
116+ {/if }
117+ </div >
118+
119+ <dialog bind:this ={deleteModal } class =" modal" >
120+ <div class =" modal-box border border-red-200 bg-base-100" >
121+ <h3 class =" text-base-content text-lg font-bold" >Confirm Deletion</h3 >
122+ <p class =" text-base-content py-4" >
123+ Are you sure you want to delete this? This action cannot be undone.
124+ </p >
125+ {#if itemToDelete ?.collectionName ! == ' cps' }
126+ <p class =" text-base-content py-4" >
127+ CP cannot be restored after deletion; the character still exists.
128+ </p >
129+ {:else }
130+ <p class =" text-base-content py-4" >
131+ Once a character is deleted, it cannot be recovered, and the associated CP will also be
132+ deleted.
133+ </p >
134+ {/if }
135+
136+ <div class =" modal-action" >
137+ <form method =" dialog" >
138+ <button class =" btn btn-ghost" >Cancel</button >
139+ </form >
140+ <button class ="btn text-white btn-soft btn-error" onclick ={confirmDelete }> Delete </button >
141+ </div >
142+ </div >
143+
144+ <form method =" dialog" class =" modal-backdrop" >
145+ <button >close</button >
146+ </form >
147+ </dialog >
0 commit comments