Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/create individual #52

Merged
merged 10 commits into from
Dec 22, 2024
Merged
39 changes: 39 additions & 0 deletions scripts/deleteConversation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import dotenv from 'dotenv';
dotenv.config();

import { adminDb } from '../src/lib/server/firebase';

async function deleteAllConversationsInSession(sessionId: string) {
try {
// 1. 獲取所有群組
const groupsSnapshot = await adminDb
.collection('sessions')
.doc(sessionId)
.collection('groups')
.get();

// 2. 遍歷每個群組
for (const groupDoc of groupsSnapshot.docs) {
// 3. 獲取該群組下所有的對話
const conversationsSnapshot = await groupDoc.ref.collection('conversations').get();

// 4. 刪除每個對話
const deletePromises = conversationsSnapshot.docs.map(async (doc) => {
await doc.ref.delete();
console.log(`已刪除對話: ${doc.id} (群組 ${groupDoc.id})`);
});

// 5. 等待該群組的所有刪除操作完成
await Promise.all(deletePromises);
console.log(`群組 ${groupDoc.id} 的所有對話已刪除`);
}

console.log(`Session ${sessionId} ���所有對話刪除成功`);
} catch (error) {
console.error('刪除對話時發生錯誤:', error);
}
}

// 使用方式:傳入要刪除的 session ID
const sessionId = 'VJgvzmbRuWwqR8kH4MMz'; // 替換成要刪除的 session ID
deleteAllConversationsInSession(sessionId).catch(console.error);
136 changes: 87 additions & 49 deletions src/lib/components/session/HostView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
import { writable } from 'svelte/store';
import { getUser } from '$lib/utils/getUser';
import type { Conversation } from '$lib/schema/conversation';
import { getUserProgress } from '$lib/utils/getUserProgress';
import { Modal } from 'flowbite-svelte';
import Chatroom from '$lib/components/Chatroom.svelte';
import { X } from 'lucide-svelte';
import { SvelteMap } from 'svelte/reactivity';

let { session }: { session: Readable<Session> } = $props();
type GroupWithId = Group & { id: string };
Expand All @@ -28,7 +28,7 @@
progress: number;
completedTasks: boolean[];
};
let participantProgress = $state(new Map<string, ParticipantProgress>());
let participantProgress = $state(new SvelteMap<string, ParticipantProgress>());
let showChatHistory = $state(false);
let selectedParticipant = $state<{
displayName: string;
Expand All @@ -42,9 +42,11 @@
} | null>(null);

onMount(() => {
const initializeSession = async () => {
const unsubscribes: (() => void)[] = [];
const initializeSession = () => {
try {
const groupsCollection = collection(db, `sessions/${$page.params.id}/groups`);
const groupChecked = new Set<string>();
const unsubscribe = onSnapshot(groupsCollection, (snapshot) => {
const groupsData: GroupWithId[] = snapshot.docs.map(
(doc) => ({ id: doc.id, ...doc.data() }) as GroupWithId
Expand All @@ -61,57 +63,95 @@
participantNames.set(participant, '未知使用者');
}
}

if (!groupChecked.has(group.id)) {
groupChecked.add(group.id);

const conversationsRef = collection(
db,
`sessions/${$page.params.id}/groups/${group.id}/conversations`
);
const unsubscribe = onSnapshot(conversationsRef, async (snapshot) => {
const conversations = snapshot.docs.map((doc) => doc.data() as Conversation);
for (const conv of conversations) {
const userData = await getUser(conv.userId);
const totalTasks = conv.subtasks.length;
const completedCount = conv.subtaskCompleted.filter(Boolean).length;
const progress = totalTasks > 0 ? (completedCount / totalTasks) * 100 : 0;

participantProgress.set(conv.userId, {
displayName: userData.displayName,
progress,
completedTasks: conv.subtaskCompleted
});
}
});
unsubscribes.push(unsubscribe);
}
});
});
return unsubscribe;
unsubscribes.push(unsubscribe);
} catch (error) {
console.error('無法加載群組資料:', error);
}
};

initializeSession();

for (const group of $groups) {
for (const participant of group.participants) {
const conversationsRef = collection(
db,
`sessions/${$page.params.id}/groups/${group.id}/conversations`
);
onSnapshot(conversationsRef, async (snapshot) => {
const conversations = snapshot.docs
.map((doc) => doc.data() as Conversation)
.filter((conv) => conv.userId === participant);

if (conversations.length > 0) {
const conv = conversations[0];
const userData = await getUser(participant);
const totalTasks = conv.subtasks.length;
const completedCount = conv.subtaskCompleted.filter(Boolean).length;
const progress = totalTasks > 0 ? (completedCount / totalTasks) * 100 : 0;

participantProgress.set(participant, {
displayName: userData.displayName,
progress,
completedTasks: conv.subtaskCompleted
});
}
});
}
}

return () => {
initializeSession().then((unsubscribe) => unsubscribe?.());
unsubscribes.forEach((unsubscribe) => unsubscribe());
};
});

async function handleStartSession() {
const response = await fetch(`/api/session/${$page.params.id}/action/start-individual`, {
method: 'POST'
});
try {
// 為每個群組的每個參與者創建對話
for (const group of $groups) {
for (const participant of group.participants) {
const response = await fetch(
`/api/session/${$page.params.id}/group/${group.id}/conversations`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
task: $session?.task || '',
subtasks: $session?.subtasks || [],
resources: $session?.resources.map((r) => r.content) || [],
participant: participant
})
}
);

if (!response.ok) {
const data = await response.json();
console.error('Failed to start session:', data.error);
if (!response.ok) {
const data = await response.json();
notifications.error(
data.error || `無法為參與者 ${participantNames.get(participant)} 創建對話`
);
return;
}
}
}

// 更新 session 狀態
const statusResponse = await fetch(
`/api/session/${$page.params.id}/action/start-individual`,
{
method: 'POST'
}
);

if (!statusResponse.ok) {
const data = await statusResponse.json();
notifications.error(data.error || '無法開始個人階段');
return;
}

notifications.success('成功開始個人階段', 3000);
} catch (error) {
console.error('無法開始個人階段:', error);
notifications.error('無法開始個人階段');
}
}

Expand Down Expand Up @@ -296,11 +336,7 @@
<ul class="space-y-2">
{#each group.participants as participant}
<li class="space-y-1">
{#await getUserProgress($page.params.id, group.id, participant)}
<div class="flex items-center justify-between text-sm">
<span class="text-xs">Loading...</span>
</div>
{:then progress}
{#if participantProgress.has(participant)}
<div class="flex items-center gap-2">
<span
class="min-w-[60px] cursor-pointer text-xs hover:text-primary-600"
Expand All @@ -310,10 +346,10 @@
role="button"
tabindex="0"
>
{progress.displayName}
{participantProgress.get(participant)?.displayName}
</span>
<div class="flex h-2">
{#each progress.completedTasks as completed, i}
{#each participantProgress.get(participant)?.completedTasks || [] as completed, i}
<div
class="h-full w-8 border-r border-white first:rounded-l last:rounded-r last:border-r-0 {completed
? 'bg-green-500'
Expand All @@ -330,9 +366,11 @@
<X class="h-4 w-4" />
</button>
</div>
{:catch}
<div class="text-xs text-red-500">Error loading progress</div>
{/await}
{:else}
<div class="flex items-center justify-between text-sm">
<span class="text-xs">Loading...</span>
</div>
{/if}
</li>
{/each}
</ul>
Expand Down
Loading
Loading