Skip to content

Commit c0ca8ba

Browse files
authored
Merge branch 'main' into fix/redirection-issues
2 parents 7cbc342 + 91ab6c7 commit c0ca8ba

38 files changed

+2084
-269
lines changed

apps/web/app/(app)/app/call/[id]/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ interface RemoteStream {
273273

274274
const recordCallParticipation = async (callId: string) => {
275275
try {
276+
276277
await fetch(`${process.env.BACKEND_URL}/api/calls/record-participation`, {
277278
method: "POST",
278279
headers: {
@@ -281,6 +282,7 @@ const recordCallParticipation = async (callId: string) => {
281282
credentials: "include",
282283
body: JSON.stringify({ callId }),
283284
});
285+
284286
} catch (error) {
285287
console.error("Error recording call participation:", error);
286288
}
@@ -321,8 +323,10 @@ export default function CallPreviewPage() {
321323
const fetchCreatorInfo = async () => {
322324
try {
323325
const response = await fetch(
326+
324327
`${process.env.BACKEND_URL}/api/calls/${callId}/creator`,
325328
{
329+
326330
credentials: "include",
327331
}
328332
);
@@ -939,6 +943,7 @@ export default function CallPreviewPage() {
939943
const handleHangup = useCallback(async () => {
940944
try {
941945
// Record that the user is leaving the call
946+
942947
await fetch(`${process.env.BACKEND_URL}/api/calls/record-leave`, {
943948
method: "POST",
944949
headers: {
@@ -947,6 +952,7 @@ export default function CallPreviewPage() {
947952
credentials: "include",
948953
body: JSON.stringify({ callId }),
949954
});
955+
950956
} catch (error) {
951957
console.error("Failed to record call leave:", error);
952958
// Continue with hangup even if recording fails
@@ -1007,6 +1013,7 @@ export default function CallPreviewPage() {
10071013
// Record that the user is leaving the call if they were joined
10081014
if (joined) {
10091015
try {
1016+
10101017
await fetch(`${process.env.BACKEND_URL}/api/calls/record-leave`, {
10111018
method: "POST",
10121019
headers: {
@@ -1015,6 +1022,7 @@ export default function CallPreviewPage() {
10151022
credentials: "include",
10161023
body: JSON.stringify({ callId }),
10171024
});
1025+
10181026
} catch (error) {
10191027
console.error("Failed to record call leave on cleanup:", error);
10201028
}

apps/web/components/app/section/team-section.tsx

Lines changed: 19 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
"use client";
22

3-
import { useSession } from "@/hooks/useSession";
3+
import { useModal } from "@/hooks/use-modal";
4+
import { CALLS_QUERY, TEAMS_QUERY } from "@/lib/QUERIES";
45
import type { Team } from "@/lib/types";
5-
import {
6-
AlertDialog,
7-
AlertDialogContent,
8-
AlertDialogHeader,
9-
AlertDialogTitle,
10-
} from "@call/ui/components/alert-dialog";
116
import { Button } from "@call/ui/components/button";
127
import {
138
Card,
@@ -23,23 +18,15 @@ import {
2318
DropdownMenuSeparator,
2419
DropdownMenuTrigger,
2520
} from "@call/ui/components/dropdown-menu";
21+
import { LoadingButton } from "@call/ui/components/loading-button";
22+
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2623
import { MoreHorizontal, Users } from "lucide-react";
2724
import { useRouter } from "next/navigation";
28-
import { useEffect, useState } from "react";
29-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
30-
import { TEAMS_QUERY } from "@/lib/QUERIES";
3125
import { toast } from "sonner";
3226

3327
export const TeamSection = () => {
3428
const queryClient = useQueryClient();
35-
const { session, isLoading: sessionLoading } = useSession();
36-
const [mounted, setMounted] = useState(false);
37-
const [addUsersOpen, setAddUsersOpen] = useState<string | null>(null); // teamId or null
38-
const [contacts, setContacts] = useState<any[]>([]);
39-
const [selectedContacts, setSelectedContacts] = useState<string[]>([]);
40-
const [addLoading, setAddLoading] = useState(false);
41-
const [addError, setAddError] = useState<string | null>(null);
42-
const [startingMeeting, setStartingMeeting] = useState<string | null>(null);
29+
const { onOpen } = useModal();
4330
const router = useRouter();
4431

4532
const {
@@ -63,6 +50,7 @@ export const TeamSection = () => {
6350
},
6451
});
6552

53+
6654
// Prevent hydration mismatch
6755
useEffect(() => {
6856
setMounted(true);
@@ -81,15 +69,8 @@ export const TeamSection = () => {
8169
teamId: team.id,
8270
}),
8371
});
84-
85-
if (!res.ok) {
86-
const data = await res.json();
87-
alert(data.message || "Failed to start meeting");
88-
return;
89-
}
90-
91-
const data = await res.json();
9272
router.push(`/app/call/${data.callId}`);
73+
9374
} catch (err) {
9475
alert("Network error starting meeting");
9576
} finally {
@@ -118,52 +99,16 @@ export const TeamSection = () => {
11899
body: JSON.stringify({ emails: selectedContacts }),
119100
});
120101

121-
const data = await res.json();
122-
if (!res.ok) {
123-
setAddError(data.message || "Failed to add users");
124-
} else {
125-
setAddUsersOpen(null);
126-
setSelectedContacts([]);
127-
// Invalidate teams query to refresh the list
128-
queryClient.invalidateQueries({ queryKey: ["teams"] });
129-
}
130-
} catch (err) {
131-
setAddError("Network error adding users");
132-
} finally {
133-
setAddLoading(false);
134-
}
135-
};
136102

137-
// Show loading state during initial mount to prevent hydration mismatch
138-
if (!mounted || sessionLoading) {
139-
return (
140-
<div className="space-y-6">
141-
<div className="flex items-center justify-between">
142-
<div>
143-
<h1 className="text-2xl font-bold">Teams</h1>
144-
<p className="text-muted-foreground">
145-
Manage your teams and collaborate with others
146-
</p>
147-
</div>
148-
</div>
149-
<div className="flex h-32 items-center justify-center">
150-
<p className="text-muted-foreground">Loading...</p>
151-
</div>
152-
</div>
153-
);
154-
}
155-
156-
if (!session?.user) {
157-
return (
158-
<div className="flex h-64 items-center justify-center">
159-
<p className="text-muted-foreground">Please sign in to view teams</p>
160-
</div>
161-
);
162-
}
103+
const startTeamMeeting = async (team: Team) => {
104+
createCall({
105+
name: `${team.name} Meeting`,
106+
members: team.members.map((m) => m.email),
107+
});
108+
};
163109

164110
return (
165111
<div className="space-y-6 px-10">
166-
{/* Header */}
167112
<div className="flex items-center justify-between">
168113
<div>
169114
<h1 className="text-2xl font-bold">Teams</h1>
@@ -220,7 +165,7 @@ export const TeamSection = () => {
220165
Leave
221166
</DropdownMenuItem>
222167
<DropdownMenuItem
223-
onClick={() => setAddUsersOpen(team.id)}
168+
onClick={() => onOpen("add-member-to-team", { team })}
224169
>
225170
Add users
226171
</DropdownMenuItem>
@@ -257,100 +202,18 @@ export const TeamSection = () => {
257202
)}
258203
</div>
259204
</div>
260-
261-
{/* Action Button */}
262-
<Button
263-
className="w-full"
264-
variant="outline"
205+
<LoadingButton
265206
onClick={() => startTeamMeeting(team)}
266-
disabled={startingMeeting === team.id}
207+
loading={createCallPending}
208+
className="w-full"
267209
>
268-
{startingMeeting === team.id
269-
? "Starting..."
270-
: "Start Meeting"}
271-
</Button>
210+
Start Meeting
211+
</LoadingButton>
272212
</CardContent>
273213
</Card>
274214
))}
275215
</div>
276216
)}
277-
278-
{/* Modal for adding users to team */}
279-
<AlertDialog
280-
open={!!addUsersOpen}
281-
onOpenChange={(open: boolean) => {
282-
if (!open) setAddUsersOpen(null);
283-
}}
284-
>
285-
<AlertDialogContent>
286-
<AlertDialogHeader>
287-
<AlertDialogTitle>Add users to team</AlertDialogTitle>
288-
</AlertDialogHeader>
289-
<div className="max-h-64 space-y-2 overflow-y-auto rounded-md border p-2">
290-
{contacts.length === 0 ? (
291-
<p className="text-muted-foreground py-4 text-center text-sm">
292-
No contacts available
293-
</p>
294-
) : (
295-
contacts.map((contact, idx) => (
296-
<div
297-
key={contact.id || contact.email || idx}
298-
className="hover:bg-muted flex items-center justify-between rounded p-2"
299-
>
300-
<div className="flex-1">
301-
<p className="text-sm font-medium">
302-
{contact.name || contact.email}
303-
</p>
304-
<p className="text-muted-foreground text-xs">
305-
{contact.email}
306-
</p>
307-
</div>
308-
<Button
309-
type="button"
310-
variant={
311-
selectedContacts.includes(contact.email)
312-
? "default"
313-
: "outline"
314-
}
315-
size="sm"
316-
onClick={() =>
317-
setSelectedContacts((prev) =>
318-
prev.includes(contact.email)
319-
? prev.filter((e) => e !== contact.email)
320-
: [...prev, contact.email]
321-
)
322-
}
323-
disabled={addLoading}
324-
>
325-
{selectedContacts.includes(contact.email) ? "Added" : "Add"}
326-
</Button>
327-
</div>
328-
))
329-
)}
330-
</div>
331-
{addError && (
332-
<div className="mt-2 text-sm text-red-500">{addError}</div>
333-
)}
334-
<div className="mt-4 flex flex-col gap-3">
335-
<Button
336-
onClick={handleAddUsers}
337-
disabled={addLoading || selectedContacts.length === 0}
338-
className="w-full"
339-
>
340-
{addLoading ? "Adding..." : "Add Selected"}
341-
</Button>
342-
<Button
343-
variant="outline"
344-
onClick={() => setAddUsersOpen(null)}
345-
className="w-full"
346-
type="button"
347-
disabled={addLoading}
348-
>
349-
Cancel
350-
</Button>
351-
</div>
352-
</AlertDialogContent>
353-
</AlertDialog>
354217
</div>
355218
);
356219
};

0 commit comments

Comments
 (0)