Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | 39x 39x 39x 39x 39x 39x 39x 20x 20x 3x 17x 16x 20x 20x 1x 19x 19x 18x 1x 19x 19x 19x 1x 1x 1x 20x 20x 39x 2x 2x 2x 1x 1x 1x 1x 39x 2x 2x 2x 3x 2x 39x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 39x 39x 16x 39x | /**
* 评论业务逻辑 Hook
* 职责:封装评论相关的数据获取和操作逻辑
*/
import { useCallback, useEffect, useState } from 'react';
import { supabaseCommentService, type Comment } from '@/src/lib/supabase';
import { showAlert } from '@/src/components/dialogs';
interface UseCommentsOptions {
targetType: 'catfood' | 'post' | 'report';
targetId: number;
pageSize?: number;
}
interface UseCommentsReturn {
comments: Comment[];
isLoading: boolean;
isRefreshing: boolean;
hasMore: boolean;
page: number;
totalCount: number;
loadComments: (pageNum?: number, refresh?: boolean) => Promise<void>;
createComment: (content: string) => Promise<void>;
deleteComment: (commentId: number) => Promise<void>;
toggleLike: (commentId: number) => Promise<void>;
refresh: () => Promise<void>;
}
/**
* 评论管理 Hook
*/
export function useComments({
targetType,
targetId,
pageSize = 20,
}: UseCommentsOptions): UseCommentsReturn {
const [comments, setComments] = useState<Comment[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isRefreshing, setIsRefreshing] = useState(false);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [totalCount, setTotalCount] = useState(0);
/**
* 加载评论列表
*/
const loadComments = useCallback(
async (pageNum: number = 1, refresh: boolean = false) => {
try {
if (refresh) {
setIsRefreshing(true);
} else if (pageNum === 1) {
setIsLoading(true);
}
const { data, error } = await supabaseCommentService.getComments({
targetType,
targetId,
parentId: null, // 只获取顶级评论
orderBy: 'created_at',
limit: pageSize,
offset: (pageNum - 1) * pageSize,
});
if (error) {
throw new Error(error.message);
}
// 防御性编程:确保 data 是数组
const results = Array.isArray(data) ? data : [];
if (refresh || pageNum === 1) {
setComments(results);
} else {
setComments((prev) => [...prev, ...results]);
}
setHasMore(results.length === pageSize);
setPage(pageNum);
setTotalCount(results.length); // Note: Supabase 版本需要单独查询 count
} catch (error) {
console.error('加载评论失败:', error);
// 出错时设置为空数组,避免 undefined
setComments([]);
showAlert({
title: '加载失败',
message: '无法加载评论列表',
type: 'error',
});
} finally {
setIsLoading(false);
setIsRefreshing(false);
}
},
[targetType, targetId, pageSize]
);
/**
* 创建评论
*/
const createComment = useCallback(
async (content: string) => {
try {
const { error } = await supabaseCommentService.createComment({
content,
targetId,
targetType,
});
if (error) {
throw new Error(error.message);
}
// 静默刷新评论列表,不弹窗提示
await loadComments(1, true);
} catch (error: any) {
console.error('发表评论失败:', error);
throw new Error(error.message || '发表评论失败');
}
},
[targetId, targetType, loadComments]
);
/**
* 删除评论
*/
const deleteComment = useCallback(async (commentId: number) => {
try {
const { error } = await supabaseCommentService.deleteComment(commentId);
Iif (error) {
throw new Error(error.message);
}
setComments((prev) => prev.filter((c) => c.id !== commentId));
setTotalCount((prev) => Math.max(0, prev - 1));
// 静默删除,不弹窗提示
} catch (error) {
console.error('删除评论失败:', error);
throw new Error('删除失败');
}
}, []);
/**
* 切换点赞状态
*/
const toggleLike = useCallback(async (commentId: number) => {
try {
const { data, error } = await supabaseCommentService.toggleCommentLike(commentId);
if (error) {
throw new Error(error.message);
}
Iif (!data) {
throw new Error('操作失败');
}
// 更新本地状态
setComments((prev) =>
prev.map((comment) =>
comment.id === commentId
? {
...comment,
likes: data.likes,
isLiked: data.liked,
}
: comment
)
);
} catch (error) {
console.error('点赞失败:', error);
throw new Error('操作失败');
}
}, []);
/**
* 刷新评论列表
*/
const refresh = useCallback(() => loadComments(1, true), [loadComments]);
// 初始加载
useEffect(() => {
loadComments();
}, [loadComments]);
return {
comments,
isLoading,
isRefreshing,
hasMore,
page,
totalCount,
loadComments,
createComment,
deleteComment,
toggleLike,
refresh,
};
}
|