create-bluecopa-react-app 1.0.20 → 1.0.22
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.
- package/bin/create-bluecopa-react-app.js +6 -7
- package/package.json +1 -1
- package/templates/latest/app/components/app-sidebar.tsx +5 -0
- package/templates/latest/app/routes/apitest.tsx +1963 -0
- package/templates/latest/app/routes/comments.tsx +96 -60
- package/templates/latest/app/routes.tsx +2 -0
- package/templates/latest/dist/assets/{__federation_expose_App-CcOhEUCE.js → __federation_expose_App-rkiN5ftu.js} +1 -1
- package/templates/latest/dist/assets/{client-uh-HfYnI.js → client-CjZD2orr.js} +5762 -4345
- package/templates/latest/dist/assets/{index-C1IOBHtM.js → index-BIZxzud9.js} +1 -1
- package/templates/latest/dist/assets/remoteEntry.css +130 -0
- package/templates/latest/dist/assets/remoteEntry.js +1 -1
- package/templates/latest/dist/index.html +2 -2
- package/templates/latest/package-lock.json +82 -8
- package/templates/latest/package.json +2 -1
|
@@ -1,12 +1,24 @@
|
|
|
1
|
-
import React, { useState } from
|
|
1
|
+
import React, { useState } from "react";
|
|
2
2
|
import { AppSidebar } from "~/components/app-sidebar";
|
|
3
3
|
import { SiteHeader } from "~/components/site-header";
|
|
4
4
|
import { SidebarInset, SidebarProvider } from "~/components/ui/sidebar";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardDescription,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from "~/components/ui/card";
|
|
6
12
|
import { Button } from "~/components/ui/button";
|
|
7
13
|
import { Input } from "~/components/ui/input";
|
|
8
14
|
import { Label } from "~/components/ui/label";
|
|
9
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
Select,
|
|
17
|
+
SelectContent,
|
|
18
|
+
SelectItem,
|
|
19
|
+
SelectTrigger,
|
|
20
|
+
SelectValue,
|
|
21
|
+
} from "~/components/ui/select";
|
|
10
22
|
import { Badge } from "~/components/ui/badge";
|
|
11
23
|
import { Separator } from "~/components/ui/separator";
|
|
12
24
|
import { Avatar, AvatarFallback } from "~/components/ui/avatar";
|
|
@@ -21,15 +33,23 @@ import {
|
|
|
21
33
|
useSubscribeUser,
|
|
22
34
|
useUnsubscribeUser,
|
|
23
35
|
useCheckSubscriptionStatus,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
} from "@bluecopa/react";
|
|
37
|
+
import {
|
|
38
|
+
MessageSquare,
|
|
39
|
+
Plus,
|
|
40
|
+
Send,
|
|
41
|
+
Edit,
|
|
42
|
+
Trash2,
|
|
43
|
+
Bell,
|
|
44
|
+
BellOff,
|
|
45
|
+
Users,
|
|
46
|
+
} from "lucide-react";
|
|
27
47
|
|
|
28
48
|
// Mock user data - in real app this would come from auth context
|
|
29
49
|
const MOCK_USER = {
|
|
30
|
-
id:
|
|
31
|
-
name:
|
|
32
|
-
email:
|
|
50
|
+
id: "user-123",
|
|
51
|
+
name: "John Doe",
|
|
52
|
+
email: "john@example.com",
|
|
33
53
|
};
|
|
34
54
|
|
|
35
55
|
// Component types for better organization
|
|
@@ -55,15 +75,15 @@ interface SubscriptionControlsProps {
|
|
|
55
75
|
|
|
56
76
|
// Thread Creation Form Component
|
|
57
77
|
function ThreadForm({ onThreadCreated }: ThreadFormProps) {
|
|
58
|
-
const [componentId, setComponentId] = useState(
|
|
59
|
-
const [componentType, setComponentType] = useState<string>(
|
|
78
|
+
const [componentId, setComponentId] = useState("");
|
|
79
|
+
const [componentType, setComponentType] = useState<string>("");
|
|
60
80
|
|
|
61
81
|
const createThreadMutation = useCreateThread({
|
|
62
82
|
onSuccess: (data) => {
|
|
63
|
-
toast.success(
|
|
64
|
-
onThreadCreated(data.data.id ||
|
|
65
|
-
setComponentId(
|
|
66
|
-
setComponentType(
|
|
83
|
+
toast.success("Thread created successfully!");
|
|
84
|
+
onThreadCreated(data.data.id || "");
|
|
85
|
+
setComponentId("");
|
|
86
|
+
setComponentType("");
|
|
67
87
|
},
|
|
68
88
|
onError: (error) => {
|
|
69
89
|
toast.error(`Failed to create thread: ${error.message}`);
|
|
@@ -73,7 +93,7 @@ function ThreadForm({ onThreadCreated }: ThreadFormProps) {
|
|
|
73
93
|
const handleSubmit = (e: React.FormEvent) => {
|
|
74
94
|
e.preventDefault();
|
|
75
95
|
if (!componentId || !componentType) {
|
|
76
|
-
toast.error(
|
|
96
|
+
toast.error("Please fill in all fields");
|
|
77
97
|
return;
|
|
78
98
|
}
|
|
79
99
|
|
|
@@ -123,12 +143,12 @@ function ThreadForm({ onThreadCreated }: ThreadFormProps) {
|
|
|
123
143
|
</SelectContent>
|
|
124
144
|
</Select>
|
|
125
145
|
</div>
|
|
126
|
-
<Button
|
|
127
|
-
type="submit"
|
|
146
|
+
<Button
|
|
147
|
+
type="submit"
|
|
128
148
|
disabled={createThreadMutation.isPending}
|
|
129
149
|
className="w-full"
|
|
130
150
|
>
|
|
131
|
-
{createThreadMutation.isPending ?
|
|
151
|
+
{createThreadMutation.isPending ? "Creating..." : "Create Thread"}
|
|
132
152
|
</Button>
|
|
133
153
|
</form>
|
|
134
154
|
</CardContent>
|
|
@@ -138,12 +158,12 @@ function ThreadForm({ onThreadCreated }: ThreadFormProps) {
|
|
|
138
158
|
|
|
139
159
|
// Comment Form Component
|
|
140
160
|
function CommentForm({ threadId, onCommentPosted }: CommentFormProps) {
|
|
141
|
-
const [comment, setComment] = useState(
|
|
161
|
+
const [comment, setComment] = useState("");
|
|
142
162
|
|
|
143
163
|
const postCommentMutation = usePostComment({
|
|
144
164
|
onSuccess: () => {
|
|
145
|
-
toast.success(
|
|
146
|
-
setComment(
|
|
165
|
+
toast.success("Comment posted successfully!");
|
|
166
|
+
setComment("");
|
|
147
167
|
onCommentPosted();
|
|
148
168
|
},
|
|
149
169
|
onError: (error) => {
|
|
@@ -154,7 +174,7 @@ function CommentForm({ threadId, onCommentPosted }: CommentFormProps) {
|
|
|
154
174
|
const handleSubmit = (e: React.FormEvent) => {
|
|
155
175
|
e.preventDefault();
|
|
156
176
|
if (!comment.trim()) {
|
|
157
|
-
toast.error(
|
|
177
|
+
toast.error("Please enter a comment");
|
|
158
178
|
return;
|
|
159
179
|
}
|
|
160
180
|
|
|
@@ -162,7 +182,7 @@ function CommentForm({ threadId, onCommentPosted }: CommentFormProps) {
|
|
|
162
182
|
data: {
|
|
163
183
|
chatThreadId: threadId,
|
|
164
184
|
comment: comment.trim(),
|
|
165
|
-
parentId: threadId
|
|
185
|
+
parentId: threadId,
|
|
166
186
|
},
|
|
167
187
|
});
|
|
168
188
|
};
|
|
@@ -187,12 +207,12 @@ function CommentForm({ threadId, onCommentPosted }: CommentFormProps) {
|
|
|
187
207
|
className="min-h-[80px]"
|
|
188
208
|
/>
|
|
189
209
|
</div>
|
|
190
|
-
<Button
|
|
191
|
-
type="submit"
|
|
210
|
+
<Button
|
|
211
|
+
type="submit"
|
|
192
212
|
disabled={postCommentMutation.isPending}
|
|
193
213
|
className="w-full"
|
|
194
214
|
>
|
|
195
|
-
{postCommentMutation.isPending ?
|
|
215
|
+
{postCommentMutation.isPending ? "Posting..." : "Post Comment"}
|
|
196
216
|
</Button>
|
|
197
217
|
</form>
|
|
198
218
|
</CardContent>
|
|
@@ -201,13 +221,17 @@ function CommentForm({ threadId, onCommentPosted }: CommentFormProps) {
|
|
|
201
221
|
}
|
|
202
222
|
|
|
203
223
|
// Individual Comment Component
|
|
204
|
-
function CommentItem({
|
|
224
|
+
function CommentItem({
|
|
225
|
+
comment,
|
|
226
|
+
onCommentUpdated,
|
|
227
|
+
onCommentDeleted,
|
|
228
|
+
}: CommentItemProps) {
|
|
205
229
|
const [isEditing, setIsEditing] = useState(false);
|
|
206
|
-
const [editText, setEditText] = useState(comment.comment ||
|
|
230
|
+
const [editText, setEditText] = useState(comment.comment || "");
|
|
207
231
|
|
|
208
232
|
const updateCommentMutation = useUpdateComment({
|
|
209
233
|
onSuccess: () => {
|
|
210
|
-
toast.success(
|
|
234
|
+
toast.success("Comment updated successfully!");
|
|
211
235
|
setIsEditing(false);
|
|
212
236
|
onCommentUpdated();
|
|
213
237
|
},
|
|
@@ -218,7 +242,7 @@ function CommentItem({ comment, onCommentUpdated, onCommentDeleted }: CommentIte
|
|
|
218
242
|
|
|
219
243
|
const deleteCommentMutation = useDeleteComment({
|
|
220
244
|
onSuccess: () => {
|
|
221
|
-
toast.success(
|
|
245
|
+
toast.success("Comment deleted successfully!");
|
|
222
246
|
onCommentDeleted();
|
|
223
247
|
},
|
|
224
248
|
onError: (error) => {
|
|
@@ -228,7 +252,7 @@ function CommentItem({ comment, onCommentUpdated, onCommentDeleted }: CommentIte
|
|
|
228
252
|
|
|
229
253
|
const handleUpdate = () => {
|
|
230
254
|
if (!editText.trim()) {
|
|
231
|
-
toast.error(
|
|
255
|
+
toast.error("Comment cannot be empty");
|
|
232
256
|
return;
|
|
233
257
|
}
|
|
234
258
|
|
|
@@ -242,7 +266,7 @@ function CommentItem({ comment, onCommentUpdated, onCommentDeleted }: CommentIte
|
|
|
242
266
|
};
|
|
243
267
|
|
|
244
268
|
const handleDelete = () => {
|
|
245
|
-
if (window.confirm(
|
|
269
|
+
if (window.confirm("Are you sure you want to delete this comment?")) {
|
|
246
270
|
deleteCommentMutation.mutate(comment.id);
|
|
247
271
|
}
|
|
248
272
|
};
|
|
@@ -253,13 +277,17 @@ function CommentItem({ comment, onCommentUpdated, onCommentDeleted }: CommentIte
|
|
|
253
277
|
<div className="flex items-center gap-3">
|
|
254
278
|
<Avatar className="h-8 w-8">
|
|
255
279
|
<AvatarFallback>
|
|
256
|
-
{comment.createdBy?.charAt(0)?.toUpperCase() ||
|
|
280
|
+
{comment.createdBy?.charAt(0)?.toUpperCase() || "U"}
|
|
257
281
|
</AvatarFallback>
|
|
258
282
|
</Avatar>
|
|
259
283
|
<div>
|
|
260
|
-
<p className="font-medium text-sm">
|
|
284
|
+
<p className="font-medium text-sm">
|
|
285
|
+
{comment.createdBy || "Unknown User"}
|
|
286
|
+
</p>
|
|
261
287
|
<p className="text-xs text-muted-foreground">
|
|
262
|
-
{comment.createdDate
|
|
288
|
+
{comment.createdDate
|
|
289
|
+
? new Date(comment.createdDate).toLocaleString()
|
|
290
|
+
: "Just now"}
|
|
263
291
|
</p>
|
|
264
292
|
</div>
|
|
265
293
|
</div>
|
|
@@ -296,14 +324,14 @@ function CommentItem({ comment, onCommentUpdated, onCommentDeleted }: CommentIte
|
|
|
296
324
|
onClick={handleUpdate}
|
|
297
325
|
disabled={updateCommentMutation.isPending}
|
|
298
326
|
>
|
|
299
|
-
{updateCommentMutation.isPending ?
|
|
327
|
+
{updateCommentMutation.isPending ? "Saving..." : "Save"}
|
|
300
328
|
</Button>
|
|
301
329
|
<Button
|
|
302
330
|
size="sm"
|
|
303
331
|
variant="outline"
|
|
304
332
|
onClick={() => {
|
|
305
333
|
setIsEditing(false);
|
|
306
|
-
setEditText(comment.comment ||
|
|
334
|
+
setEditText(comment.comment || "");
|
|
307
335
|
}}
|
|
308
336
|
>
|
|
309
337
|
Cancel
|
|
@@ -319,11 +347,14 @@ function CommentItem({ comment, onCommentUpdated, onCommentDeleted }: CommentIte
|
|
|
319
347
|
|
|
320
348
|
// Subscription Controls Component
|
|
321
349
|
function SubscriptionControls({ userId, threadId }: SubscriptionControlsProps) {
|
|
322
|
-
const { data: subscriptionStatus, isLoading } = useCheckSubscriptionStatus(
|
|
350
|
+
const { data: subscriptionStatus, isLoading } = useCheckSubscriptionStatus(
|
|
351
|
+
userId,
|
|
352
|
+
threadId
|
|
353
|
+
);
|
|
323
354
|
|
|
324
355
|
const subscribeUserMutation = useSubscribeUser({
|
|
325
356
|
onSuccess: () => {
|
|
326
|
-
toast.success(
|
|
357
|
+
toast.success("Successfully subscribed to thread!");
|
|
327
358
|
},
|
|
328
359
|
onError: (error) => {
|
|
329
360
|
toast.error(`Failed to subscribe: ${error.message}`);
|
|
@@ -332,7 +363,7 @@ function SubscriptionControls({ userId, threadId }: SubscriptionControlsProps) {
|
|
|
332
363
|
|
|
333
364
|
const unsubscribeUserMutation = useUnsubscribeUser({
|
|
334
365
|
onSuccess: () => {
|
|
335
|
-
toast.success(
|
|
366
|
+
toast.success("Successfully unsubscribed from thread!");
|
|
336
367
|
},
|
|
337
368
|
onError: (error) => {
|
|
338
369
|
toast.error(`Failed to unsubscribe: ${error.message}`);
|
|
@@ -363,7 +394,9 @@ function SubscriptionControls({ userId, threadId }: SubscriptionControlsProps) {
|
|
|
363
394
|
variant={isSubscribed ? "outline" : "default"}
|
|
364
395
|
size="sm"
|
|
365
396
|
onClick={isSubscribed ? handleUnsubscribe : handleSubscribe}
|
|
366
|
-
disabled={
|
|
397
|
+
disabled={
|
|
398
|
+
subscribeUserMutation.isPending || unsubscribeUserMutation.isPending
|
|
399
|
+
}
|
|
367
400
|
>
|
|
368
401
|
{isSubscribed ? (
|
|
369
402
|
<>
|
|
@@ -386,12 +419,12 @@ function SubscriptionControls({ userId, threadId }: SubscriptionControlsProps) {
|
|
|
386
419
|
|
|
387
420
|
// Main Comments Page Component
|
|
388
421
|
export default function CommentsPage() {
|
|
389
|
-
const [selectedThreadId, setSelectedThreadId] = useState<string>(
|
|
422
|
+
const [selectedThreadId, setSelectedThreadId] = useState<string>("");
|
|
390
423
|
|
|
391
|
-
const {
|
|
392
|
-
data: commentsData,
|
|
393
|
-
isLoading: commentsLoading,
|
|
394
|
-
refetch: refetchComments
|
|
424
|
+
const {
|
|
425
|
+
data: commentsData,
|
|
426
|
+
isLoading: commentsLoading,
|
|
427
|
+
refetch: refetchComments,
|
|
395
428
|
} = useGetCommentsByThreadId(selectedThreadId, {
|
|
396
429
|
enabled: !!selectedThreadId,
|
|
397
430
|
});
|
|
@@ -440,14 +473,14 @@ export default function CommentsPage() {
|
|
|
440
473
|
{/* Left Column - Thread Creation */}
|
|
441
474
|
<div className="space-y-6">
|
|
442
475
|
<ThreadForm onThreadCreated={handleThreadCreated} />
|
|
443
|
-
|
|
476
|
+
|
|
444
477
|
{selectedThreadId && (
|
|
445
478
|
<>
|
|
446
|
-
<CommentForm
|
|
447
|
-
threadId={selectedThreadId}
|
|
448
|
-
onCommentPosted={handleCommentAction}
|
|
479
|
+
<CommentForm
|
|
480
|
+
threadId={selectedThreadId}
|
|
481
|
+
onCommentPosted={handleCommentAction}
|
|
449
482
|
/>
|
|
450
|
-
|
|
483
|
+
|
|
451
484
|
<Card>
|
|
452
485
|
<CardHeader>
|
|
453
486
|
<CardTitle className="flex items-center gap-2">
|
|
@@ -459,9 +492,9 @@ export default function CommentsPage() {
|
|
|
459
492
|
</CardDescription>
|
|
460
493
|
</CardHeader>
|
|
461
494
|
<CardContent>
|
|
462
|
-
<SubscriptionControls
|
|
463
|
-
userId={MOCK_USER.id}
|
|
464
|
-
threadId={selectedThreadId}
|
|
495
|
+
<SubscriptionControls
|
|
496
|
+
userId={MOCK_USER.id}
|
|
497
|
+
threadId={selectedThreadId}
|
|
465
498
|
/>
|
|
466
499
|
</CardContent>
|
|
467
500
|
</Card>
|
|
@@ -475,10 +508,9 @@ export default function CommentsPage() {
|
|
|
475
508
|
<CardHeader>
|
|
476
509
|
<CardTitle>Comments</CardTitle>
|
|
477
510
|
<CardDescription>
|
|
478
|
-
{selectedThreadId
|
|
511
|
+
{selectedThreadId
|
|
479
512
|
? `Comments for thread ${selectedThreadId.slice(0, 8)}...`
|
|
480
|
-
:
|
|
481
|
-
}
|
|
513
|
+
: "Create a thread to see comments"}
|
|
482
514
|
</CardDescription>
|
|
483
515
|
</CardHeader>
|
|
484
516
|
<CardContent>
|
|
@@ -524,13 +556,17 @@ export default function CommentsPage() {
|
|
|
524
556
|
<CardContent className="space-y-2">
|
|
525
557
|
<div className="flex justify-between items-center">
|
|
526
558
|
<span className="text-sm">Thread Selected:</span>
|
|
527
|
-
<Badge
|
|
559
|
+
<Badge
|
|
560
|
+
variant={selectedThreadId ? "default" : "secondary"}
|
|
561
|
+
>
|
|
528
562
|
{selectedThreadId ? "Yes" : "No"}
|
|
529
563
|
</Badge>
|
|
530
564
|
</div>
|
|
531
565
|
<div className="flex justify-between items-center">
|
|
532
566
|
<span className="text-sm">Comments Loading:</span>
|
|
533
|
-
<Badge
|
|
567
|
+
<Badge
|
|
568
|
+
variant={commentsLoading ? "default" : "secondary"}
|
|
569
|
+
>
|
|
534
570
|
{commentsLoading ? "Yes" : "No"}
|
|
535
571
|
</Badge>
|
|
536
572
|
</div>
|
|
@@ -5,6 +5,7 @@ import Comments from "./routes/comments";
|
|
|
5
5
|
import Websocket from "./routes/websocket";
|
|
6
6
|
import Payments from "./routes/payments";
|
|
7
7
|
import Statements from "./routes/statements";
|
|
8
|
+
import ApiTest from "./routes/apitest";
|
|
8
9
|
|
|
9
10
|
export default function RouteConfig() {
|
|
10
11
|
return (
|
|
@@ -14,6 +15,7 @@ export default function RouteConfig() {
|
|
|
14
15
|
<Route path="/websocket" element={<Websocket />} />
|
|
15
16
|
<Route path="/payments" element={<Payments />} />
|
|
16
17
|
<Route path="/statements" element={<Statements />} />
|
|
18
|
+
<Route path="/apitest" element={<ApiTest />} />
|
|
17
19
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
18
20
|
</Routes>
|
|
19
21
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
System.register(['./__federation_fn_import-CzfA7kmP.js', './client-
|
|
1
|
+
System.register(['./__federation_fn_import-CzfA7kmP.js', './client-CjZD2orr.js'], (function (exports, module) {
|
|
2
2
|
'use strict';
|
|
3
3
|
var importShared, clientExports, jsxRuntimeExports, MemoryRouter, BrowserRouter, App;
|
|
4
4
|
return {
|