@23blocks/react 7.5.9 → 7.5.10
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/README.md +189 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -224,6 +224,7 @@ export function ProductList() {
|
|
|
224
224
|
|------|-------------|
|
|
225
225
|
| `useSearch()` | Search with state management |
|
|
226
226
|
| `useFavorites()` | Favorites management |
|
|
227
|
+
| `useContentSeries()` | Content series management |
|
|
227
228
|
| `useUsers()` | User management (admin) |
|
|
228
229
|
| `useMfa()` | Multi-factor authentication |
|
|
229
230
|
| `useOAuth()` | OAuth operations |
|
|
@@ -449,6 +450,194 @@ export function FavoriteButton({ itemId, itemType }: Props) {
|
|
|
449
450
|
}
|
|
450
451
|
```
|
|
451
452
|
|
|
453
|
+
### useContentSeries
|
|
454
|
+
|
|
455
|
+
Manage content series (collections of ordered posts like tutorials or courses).
|
|
456
|
+
|
|
457
|
+
```tsx
|
|
458
|
+
'use client';
|
|
459
|
+
|
|
460
|
+
import { useContentSeries } from '@23blocks/react';
|
|
461
|
+
import { useEffect } from 'react';
|
|
462
|
+
|
|
463
|
+
export function SeriesList() {
|
|
464
|
+
const {
|
|
465
|
+
series,
|
|
466
|
+
totalRecords,
|
|
467
|
+
isLoading,
|
|
468
|
+
error,
|
|
469
|
+
listSeries,
|
|
470
|
+
createSeries,
|
|
471
|
+
likeSeries,
|
|
472
|
+
} = useContentSeries();
|
|
473
|
+
|
|
474
|
+
useEffect(() => {
|
|
475
|
+
listSeries({ page: 1, perPage: 10 });
|
|
476
|
+
}, [listSeries]);
|
|
477
|
+
|
|
478
|
+
if (isLoading) return <div>Loading...</div>;
|
|
479
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
480
|
+
|
|
481
|
+
return (
|
|
482
|
+
<div>
|
|
483
|
+
<p>Total: {totalRecords} series</p>
|
|
484
|
+
<ul>
|
|
485
|
+
{series.map((s) => (
|
|
486
|
+
<li key={s.uniqueId}>
|
|
487
|
+
<h3>{s.title}</h3>
|
|
488
|
+
<p>{s.description}</p>
|
|
489
|
+
<span>Posts: {s.postsCount} | Likes: {s.likes}</span>
|
|
490
|
+
<button onClick={() => likeSeries(s.uniqueId)}>Like</button>
|
|
491
|
+
</li>
|
|
492
|
+
))}
|
|
493
|
+
</ul>
|
|
494
|
+
</div>
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### Create a Series
|
|
500
|
+
|
|
501
|
+
```tsx
|
|
502
|
+
'use client';
|
|
503
|
+
|
|
504
|
+
import { useContentSeries } from '@23blocks/react';
|
|
505
|
+
|
|
506
|
+
export function CreateSeriesForm() {
|
|
507
|
+
const { createSeries, isLoading, error } = useContentSeries();
|
|
508
|
+
|
|
509
|
+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
510
|
+
e.preventDefault();
|
|
511
|
+
const formData = new FormData(e.currentTarget);
|
|
512
|
+
|
|
513
|
+
const newSeries = await createSeries({
|
|
514
|
+
title: formData.get('title') as string,
|
|
515
|
+
description: formData.get('description') as string,
|
|
516
|
+
visibility: 'public',
|
|
517
|
+
completionStatus: 'ongoing',
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
console.log('Created series:', newSeries.uniqueId);
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
return (
|
|
524
|
+
<form onSubmit={handleSubmit}>
|
|
525
|
+
<input name="title" placeholder="Series Title" required />
|
|
526
|
+
<textarea name="description" placeholder="Description" />
|
|
527
|
+
<button type="submit" disabled={isLoading}>
|
|
528
|
+
{isLoading ? 'Creating...' : 'Create Series'}
|
|
529
|
+
</button>
|
|
530
|
+
{error && <p>Error: {error.message}</p>}
|
|
531
|
+
</form>
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
#### Manage Series Posts
|
|
537
|
+
|
|
538
|
+
```tsx
|
|
539
|
+
'use client';
|
|
540
|
+
|
|
541
|
+
import { useContentSeries } from '@23blocks/react';
|
|
542
|
+
import { useEffect } from 'react';
|
|
543
|
+
|
|
544
|
+
export function SeriesPostManager({ seriesId }: { seriesId: string }) {
|
|
545
|
+
const {
|
|
546
|
+
posts,
|
|
547
|
+
currentSeries,
|
|
548
|
+
getSeries,
|
|
549
|
+
getSeriesPosts,
|
|
550
|
+
addSeriesPost,
|
|
551
|
+
removeSeriesPost,
|
|
552
|
+
reorderSeriesPosts,
|
|
553
|
+
isLoading,
|
|
554
|
+
} = useContentSeries();
|
|
555
|
+
|
|
556
|
+
useEffect(() => {
|
|
557
|
+
getSeries(seriesId);
|
|
558
|
+
getSeriesPosts(seriesId);
|
|
559
|
+
}, [seriesId, getSeries, getSeriesPosts]);
|
|
560
|
+
|
|
561
|
+
const handleAddPost = async (postId: string) => {
|
|
562
|
+
await addSeriesPost(seriesId, postId);
|
|
563
|
+
await getSeriesPosts(seriesId); // Refresh
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const handleRemovePost = async (postId: string) => {
|
|
567
|
+
await removeSeriesPost(seriesId, postId);
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
const handleReorder = async () => {
|
|
571
|
+
await reorderSeriesPosts(seriesId, {
|
|
572
|
+
posts: posts.map((p, idx) => ({
|
|
573
|
+
postUniqueId: p.uniqueId,
|
|
574
|
+
sequence: idx + 1,
|
|
575
|
+
})),
|
|
576
|
+
});
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
return (
|
|
580
|
+
<div>
|
|
581
|
+
<h2>{currentSeries?.title}</h2>
|
|
582
|
+
<p>{posts.length} posts in this series</p>
|
|
583
|
+
<ul>
|
|
584
|
+
{posts.map((post, idx) => (
|
|
585
|
+
<li key={post.uniqueId}>
|
|
586
|
+
{idx + 1}. {post.title}
|
|
587
|
+
<button onClick={() => handleRemovePost(post.uniqueId)}>
|
|
588
|
+
Remove
|
|
589
|
+
</button>
|
|
590
|
+
</li>
|
|
591
|
+
))}
|
|
592
|
+
</ul>
|
|
593
|
+
<button onClick={handleReorder} disabled={isLoading}>
|
|
594
|
+
Save Order
|
|
595
|
+
</button>
|
|
596
|
+
</div>
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
#### useContentSeries Return Type
|
|
602
|
+
|
|
603
|
+
```typescript
|
|
604
|
+
interface UseContentSeriesReturn {
|
|
605
|
+
// State
|
|
606
|
+
series: Series[]; // List of series
|
|
607
|
+
currentSeries: Series | null; // Currently loaded series
|
|
608
|
+
posts: Post[]; // Posts in current series
|
|
609
|
+
totalRecords: number; // Total series count
|
|
610
|
+
isLoading: boolean; // Loading state
|
|
611
|
+
error: Error | null; // Error state
|
|
612
|
+
|
|
613
|
+
// CRUD Operations
|
|
614
|
+
listSeries(params?: ListSeriesParams): Promise<PageResult<Series>>;
|
|
615
|
+
querySeries(params: QuerySeriesParams): Promise<PageResult<Series>>;
|
|
616
|
+
getSeries(uniqueId: string): Promise<Series>;
|
|
617
|
+
createSeries(data: CreateSeriesRequest): Promise<Series>;
|
|
618
|
+
updateSeries(uniqueId: string, data: UpdateSeriesRequest): Promise<Series>;
|
|
619
|
+
deleteSeries(uniqueId: string): Promise<void>;
|
|
620
|
+
|
|
621
|
+
// Social Actions
|
|
622
|
+
likeSeries(uniqueId: string): Promise<Series>;
|
|
623
|
+
dislikeSeries(uniqueId: string): Promise<Series>;
|
|
624
|
+
followSeries(uniqueId: string): Promise<Series>;
|
|
625
|
+
unfollowSeries(uniqueId: string): Promise<void>;
|
|
626
|
+
saveSeries(uniqueId: string): Promise<Series>;
|
|
627
|
+
unsaveSeries(uniqueId: string): Promise<void>;
|
|
628
|
+
|
|
629
|
+
// Post Management
|
|
630
|
+
getSeriesPosts(uniqueId: string): Promise<Post[]>;
|
|
631
|
+
addSeriesPost(seriesId: string, postId: string, sequence?: number): Promise<void>;
|
|
632
|
+
removeSeriesPost(seriesId: string, postId: string): Promise<void>;
|
|
633
|
+
reorderSeriesPosts(uniqueId: string, data: ReorderPostsRequest): Promise<Series>;
|
|
634
|
+
|
|
635
|
+
// State Management
|
|
636
|
+
clearSeries(): void;
|
|
637
|
+
clearError(): void;
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
452
641
|
## Server-Side Rendering (SSR)
|
|
453
642
|
|
|
454
643
|
### Handling Client-Only Code
|