@walwal-harness/cli 7.1.39 → 7.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,255 @@
1
+ # API Handler Templates
2
+
3
+ ## Success/Failure Handler Types
4
+
5
+ ### 1. Toast Messages
6
+
7
+ ```tsx
8
+ // Using react-hot-toast
9
+ import toast from 'react-hot-toast';
10
+
11
+ // Success
12
+ toast.success('${message}');
13
+
14
+ // Error
15
+ toast.error('${message}');
16
+ ```
17
+
18
+ ```tsx
19
+ // Using sonner
20
+ import { toast } from 'sonner';
21
+
22
+ // Success
23
+ toast.success('${message}');
24
+
25
+ // Error
26
+ toast.error('${message}');
27
+ ```
28
+
29
+ ```tsx
30
+ // Using react-toastify
31
+ import { toast } from 'react-toastify';
32
+
33
+ // Success
34
+ toast.success('${message}');
35
+
36
+ // Error
37
+ toast.error('${message}');
38
+ ```
39
+
40
+ ### 2. Alert/Popup Dialogs
41
+
42
+ ```tsx
43
+ // Native browser alert
44
+ alert('${message}');
45
+
46
+ // Using shadcn/ui AlertDialog
47
+ import {
48
+ AlertDialog,
49
+ AlertDialogAction,
50
+ AlertDialogContent,
51
+ AlertDialogDescription,
52
+ AlertDialogFooter,
53
+ AlertDialogHeader,
54
+ AlertDialogTitle,
55
+ } from "@/components/ui/alert-dialog";
56
+
57
+ <AlertDialog open={isOpen} onOpenChange={setIsOpen}>
58
+ <AlertDialogContent>
59
+ <AlertDialogHeader>
60
+ <AlertDialogTitle>${title}</AlertDialogTitle>
61
+ <AlertDialogDescription>${message}</AlertDialogDescription>
62
+ </AlertDialogHeader>
63
+ <AlertDialogFooter>
64
+ <AlertDialogAction onClick={() => setIsOpen(false)}>
65
+ 확인
66
+ </AlertDialogAction>
67
+ </AlertDialogFooter>
68
+ </AlertDialogContent>
69
+ </AlertDialog>
70
+ ```
71
+
72
+ ### 3. Page Navigation
73
+
74
+ ```tsx
75
+ // Using Next.js App Router
76
+ import { useRouter } from 'next/navigation';
77
+
78
+ const router = useRouter();
79
+
80
+ // Success redirect
81
+ router.push('${successPath}');
82
+
83
+ // With replace (no back button)
84
+ router.replace('${successPath}');
85
+ ```
86
+
87
+ ```tsx
88
+ // Using Next.js Pages Router
89
+ import { useRouter } from 'next/router';
90
+
91
+ const router = useRouter();
92
+ router.push('${successPath}');
93
+ ```
94
+
95
+ ### 4. State Update
96
+
97
+ ```tsx
98
+ // Update local state
99
+ setData(response.data);
100
+ setLoading(false);
101
+ setError(null);
102
+
103
+ // With React Query
104
+ queryClient.invalidateQueries({ queryKey: ['${queryKey}'] });
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Combined Handler Patterns
110
+
111
+ ### Pattern A: Toast + State Update
112
+
113
+ ```tsx
114
+ const handleSuccess = (data: ResponseType) => {
115
+ toast.success('${successMessage}');
116
+ setData(data);
117
+ setLoading(false);
118
+ };
119
+
120
+ const handleError = (error: Error) => {
121
+ toast.error('${errorMessage}');
122
+ setError(error.message);
123
+ setLoading(false);
124
+ };
125
+ ```
126
+
127
+ ### Pattern B: Toast + Navigation
128
+
129
+ ```tsx
130
+ const handleSuccess = () => {
131
+ toast.success('${successMessage}');
132
+ router.push('${successPath}');
133
+ };
134
+
135
+ const handleError = (error: Error) => {
136
+ toast.error(error.message || '${errorMessage}');
137
+ };
138
+ ```
139
+
140
+ ### Pattern C: Popup Dialog + Navigation
141
+
142
+ ```tsx
143
+ const handleSuccess = () => {
144
+ setDialogConfig({
145
+ open: true,
146
+ title: '${successTitle}',
147
+ message: '${successMessage}',
148
+ onConfirm: () => router.push('${successPath}'),
149
+ });
150
+ };
151
+
152
+ const handleError = (error: Error) => {
153
+ setDialogConfig({
154
+ open: true,
155
+ title: '${errorTitle}',
156
+ message: error.message || '${errorMessage}',
157
+ onConfirm: () => setDialogConfig({ open: false }),
158
+ });
159
+ };
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Trigger Patterns
165
+
166
+ ### onLoad (페이지 로딩 시)
167
+
168
+ ```tsx
169
+ // Using useEffect
170
+ useEffect(() => {
171
+ fetchData();
172
+ }, []);
173
+
174
+ // Using React Query
175
+ const { data, isLoading, error } = useQuery({
176
+ queryKey: ['${queryKey}'],
177
+ queryFn: () => fetch('${apiPath}').then(res => res.json()),
178
+ });
179
+
180
+ // Using SWR
181
+ const { data, error, isLoading } = useSWR('${apiPath}', fetcher);
182
+ ```
183
+
184
+ ### onClick (클릭 시)
185
+
186
+ ```tsx
187
+ <button onClick={async () => {
188
+ try {
189
+ setLoading(true);
190
+ const response = await axios.${method}('${apiPath}', ${hasBody ? 'payload' : ''});
191
+ handleSuccess(response.data);
192
+ } catch (error) {
193
+ handleError(error);
194
+ }
195
+ }}>
196
+ ${buttonText}
197
+ </button>
198
+ ```
199
+
200
+ ### onSubmit (폼 제출 시)
201
+
202
+ ```tsx
203
+ const handleSubmit = async (e: React.FormEvent) => {
204
+ e.preventDefault();
205
+ try {
206
+ setLoading(true);
207
+ const response = await axios.${method}('${apiPath}', formData);
208
+ handleSuccess(response.data);
209
+ } catch (error) {
210
+ handleError(error);
211
+ }
212
+ };
213
+
214
+ <form onSubmit={handleSubmit}>
215
+ {/* form fields */}
216
+ <button type="submit" disabled={loading}>
217
+ {loading ? '처리 중...' : '${submitText}'}
218
+ </button>
219
+ </form>
220
+ ```
221
+
222
+ ### onBlur (포커스 해제 시)
223
+
224
+ ```tsx
225
+ <input
226
+ onBlur={async (e) => {
227
+ const value = e.target.value;
228
+ if (value !== previousValue) {
229
+ try {
230
+ await axios.${method}('${apiPath}', { value });
231
+ handleSuccess();
232
+ } catch (error) {
233
+ handleError(error);
234
+ }
235
+ }
236
+ }}
237
+ />
238
+ ```
239
+
240
+ ### onChange with Debounce (입력 변경 시)
241
+
242
+ ```tsx
243
+ import { useDebouncedCallback } from 'use-debounce';
244
+
245
+ const debouncedSave = useDebouncedCallback(async (value: string) => {
246
+ try {
247
+ await axios.${method}('${apiPath}', { value });
248
+ handleSuccess();
249
+ } catch (error) {
250
+ handleError(error);
251
+ }
252
+ }, 500);
253
+
254
+ <input onChange={(e) => debouncedSave(e.target.value)} />
255
+ ```