Skip to content

Commit a4b9284

Browse files
committed
fix chats auth follow-ups
1 parent 56cef16 commit a4b9284

3 files changed

Lines changed: 70 additions & 36 deletions

File tree

e2e/auth.spec.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from "@playwright/test";
2-
import { HOST_EMAIL, signIn } from "./helpers";
2+
import { HOST_EMAIL, SEEDED_THREAD_ID, signIn } from "./helpers";
33

44
test("public listing shows the seeded public listing and guest contact gate", async ({
55
page,
@@ -34,3 +34,14 @@ test("sign-in normalises unsafe redirect_to values", async ({ page }) => {
3434

3535
await expect(page).toHaveURL(/\/map$/);
3636
});
37+
38+
test("guest chats redirect preserves the requested chat path", async ({
39+
page,
40+
}) => {
41+
await page.goto(`/chats/${SEEDED_THREAD_ID}`);
42+
43+
await expect(page).toHaveURL(
44+
new RegExp(`/sign-in\\?redirect_to=/?chats/${SEEDED_THREAD_ID}$`)
45+
);
46+
await expect(page.getByTestId("sign-in-form")).toBeVisible();
47+
});

src/app/(core)/(interact)/(stretched)/chats/[[...threadId]]/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ export const metadata: Metadata = {
1717
export default async function ChatsPage({ params }: ChatsPageProps) {
1818
const { threadId: threadIdSegments } = await params;
1919
const threadId = threadIdSegments?.[0] ?? null;
20+
const redirectPath = threadId ? `/chats/${threadId}` : "/chats";
2021

2122
const supabase = await createClient();
2223
const {
2324
data: { user },
2425
} = await supabase.auth.getUser();
2526

2627
if (!user) {
27-
redirect("/sign-in");
28+
redirect(`/sign-in?redirect_to=${redirectPath}`);
2829
}
2930

3031
const { data: threads } = await supabase

src/contexts/UnreadMessagesContext.tsx

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,69 @@ export function UnreadMessagesProvider({ children }: PropsWithChildren) {
4040
{}
4141
);
4242
const [hasViewedChats, setHasViewedChats] = useState(false);
43+
const [userId, setUserId] = useState<string | null>(null);
4344
const supabase = useMemo(() => createClient(), []);
4445
const pathname = usePathname();
4546

47+
useEffect(() => {
48+
let isActive = true;
49+
50+
async function loadUserId(nextUserId?: string | null) {
51+
const resolvedUserId =
52+
nextUserId ?? (await supabase.auth.getUser()).data.user?.id ?? null;
53+
54+
if (!isActive) return;
55+
56+
setUserId((previousUserId) => {
57+
if (previousUserId !== resolvedUserId) {
58+
setUnreadCount(0);
59+
setThreadReadStatus({});
60+
setHasViewedChats(false);
61+
}
62+
63+
return resolvedUserId;
64+
});
65+
}
66+
67+
void loadUserId();
68+
69+
if (isAuthDebugEnabled) {
70+
console.log("Setting up auth listener");
71+
}
72+
73+
const {
74+
data: { subscription },
75+
} = supabase.auth.onAuthStateChange((event, session) => {
76+
if (isAuthDebugEnabled) {
77+
console.log("Auth event:", event);
78+
console.log("Session:", session ? "exists" : "none");
79+
}
80+
81+
void loadUserId(session?.user?.id ?? null);
82+
});
83+
84+
return () => {
85+
isActive = false;
86+
subscription.unsubscribe();
87+
};
88+
}, [supabase]);
89+
4690
useEffect(() => {
4791
let isActive = true;
4892

4993
async function checkUnreadMessages() {
5094
try {
51-
const {
52-
data: { user },
53-
} = await supabase.auth.getUser();
54-
55-
if (!user || !isActive) return;
95+
if (!userId) {
96+
if (isActive) {
97+
setUnreadCount(0);
98+
}
99+
return;
100+
}
56101

57102
const { data: unreadMessages, error } = await supabase
58103
.from("chat_messages")
59104
.select("id")
60-
.neq("sender_id", user.id)
105+
.neq("sender_id", userId)
61106
.is("read_at", null);
62107

63108
if (error) {
@@ -79,45 +124,22 @@ export function UnreadMessagesProvider({ children }: PropsWithChildren) {
79124
return () => {
80125
isActive = false;
81126
};
82-
}, [supabase]);
127+
}, [supabase, userId]);
83128

84129
useEffect(() => {
85130
if (pathname === "/chats") {
86131
setHasViewedChats(true);
87132
}
88133
}, [pathname]);
89134

90-
useEffect(() => {
91-
if (isAuthDebugEnabled) {
92-
console.log("Setting up auth listener");
93-
}
94-
95-
const {
96-
data: { subscription },
97-
} = supabase.auth.onAuthStateChange((event, session) => {
98-
if (!isAuthDebugEnabled) return;
99-
100-
console.log("Auth event:", event);
101-
console.log("Session:", session ? "exists" : "none");
102-
});
103-
104-
return () => {
105-
subscription.unsubscribe();
106-
};
107-
}, [supabase]);
108-
109135
useEffect(() => {
110136
let activeChannel: ReturnType<typeof supabase.channel> | null = null;
111137

112138
async function setupSubscription() {
113-
const {
114-
data: { user },
115-
} = await supabase.auth.getUser();
116-
117-
if (!user) return;
139+
if (!userId) return;
118140

119141
activeChannel = supabase
120-
.channel("chat_messages")
142+
.channel(`chat_messages:${userId}`)
121143
.on(
122144
"postgres_changes",
123145
{
@@ -128,7 +150,7 @@ export function UnreadMessagesProvider({ children }: PropsWithChildren) {
128150
async (payload) => {
129151
const message = payload.new as ChatMessagePayload;
130152

131-
if (message.sender_id === user.id) return;
153+
if (message.sender_id === userId) return;
132154

133155
const currentPath = window.location.pathname;
134156

@@ -167,7 +189,7 @@ export function UnreadMessagesProvider({ children }: PropsWithChildren) {
167189
supabase.removeChannel(activeChannel);
168190
}
169191
};
170-
}, [supabase]);
192+
}, [supabase, userId]);
171193

172194
function markThreadAsRead(threadId: string) {
173195
setThreadReadStatus((previousStatus) => ({

0 commit comments

Comments
 (0)