Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 66 additions & 7 deletions app/(auth)/accept-invite/page.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,56 @@
"use client";

import { useState } from "react";
import { useSearchParams } from "next/navigation";
import { useSearchParams, useRouter } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { authClient } from "@/lib/auth/client";
import { authClient, useSession } from "@/lib/auth/client";
import { toast } from "sonner";

export default function AcceptInvitePage() {
const router = useRouter();
const searchParams = useSearchParams();
const email = searchParams.get("email") || "";
const emailFromUrl = searchParams.get("email") || "";
const invitationId = searchParams.get("invitationId") || "";
const [email, setEmail] = useState(emailFromUrl);
const [isLoading, setIsLoading] = useState(false);
const [isAccepting, setIsAccepting] = useState(false);
const [sent, setSent] = useState(false);
const { data: session, isPending } = useSession();

async function handleAcceptInvitation() {
setIsAccepting(true);
try {
const result = await authClient.organization.acceptInvitation({
invitationId,
});

if (result.error) {
toast.error(result.error.message || "Failed to accept invitation");
} else {
toast.success("Invitation accepted!");
router.push("/start");
}
} catch (error) {
console.error("Accept invitation error:", error);
toast.error("Failed to accept invitation");
} finally {
setIsAccepting(false);
}
}

async function handleSignIn() {
if (!email) {
toast.error("No email provided");
toast.error("Please enter your email");
return;
}

setIsLoading(true);
try {
const result = await authClient.signIn.magicLink({
email,
callbackURL: "/start",
callbackURL: `/accept-invite?email=${encodeURIComponent(email)}${invitationId ? `&invitationId=${invitationId}` : ""}`,
});

if (result.error) {
Expand All @@ -41,6 +67,39 @@ export default function AcceptInvitePage() {
}
}

if (isPending) {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="text-muted-foreground">Loading...</div>
</div>
);
}

if (session?.user) {
return (
<div className="flex min-h-screen items-center justify-center">
<div className="w-full max-w-md space-y-6 p-8">
<div className="text-center space-y-2">
<h1 className="text-2xl font-bold">Accept Invitation</h1>
<p className="text-muted-foreground">
You're signed in as <strong>{session.user.email}</strong>
</p>
</div>

<Button
onClick={handleAcceptInvitation}
disabled={isAccepting}
className="w-full"
>
{isAccepting
? "Accepting..."
: "Accept invitation & join workspace"}
</Button>
</div>
</div>
);
}

if (sent) {
return (
<div className="flex min-h-screen items-center justify-center">
Expand Down Expand Up @@ -76,8 +135,8 @@ export default function AcceptInvitePage() {
id="email"
type="email"
value={email}
disabled
className="bg-muted"
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
/>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default function Events() {
const [selectedDate, setSelectedDate] = useState<string | null>(null);

const calendarSubscriptionUrl = useMemo(
() => `/api/calendar/${tenant}/${projectId}/calendar.ics?userId=${session?.user?.id}`,
() =>
`/api/calendar/${tenant}/${projectId}/calendar.ics?userId=${session?.user?.id}`,
[tenant, projectId, session?.user?.id],
);

Expand Down
2 changes: 1 addition & 1 deletion app/(dashboard)/[tenant]/today/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default function Today() {
});

const projects = projectsData?.projects;
const isOrgAdmin = projectsData?.isOrgAdmin ?? (tenant === "me");
const isOrgAdmin = projectsData?.isOrgAdmin ?? tenant === "me";

const { dueToday = [], overDue = [], events = [] } = todayData ?? {};

Expand Down
3 changes: 2 additions & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ClientRedirect } from "@/components/core/client-redirect";
import { Footer } from "@/components/layout/footer";
import { Header } from "@/components/layout/header";
import { auth } from "@/lib/auth";
import { isSignupDisabled } from "@/lib/config";

export default async function Home() {
const session = await auth.api.getSession({
Expand All @@ -16,7 +17,7 @@ export default async function Home() {

return (
<div className="min-h-screen">
<Header />
<Header disableSignups={isSignupDisabled()} />

<section>
<div className="mx-auto max-w-7xl relative border border-gray-200 dark:border-gray-800 pb-24 pt-8 px-6">
Expand Down
6 changes: 6 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.5/schema.json",
"assist": { "actions": { "source": { "organizeImports": "on" } } },
"css": {
"parser": {
"cssModules": true,
"tailwindDirectives": true
}
},
"linter": {
"enabled": true,
"rules": {
Expand Down
12 changes: 9 additions & 3 deletions components/core/billing.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"use client";

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";

export function Billing() {
return (
Expand All @@ -13,8 +19,8 @@ export function Billing() {
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">
No billing is required for self-hosted instances.
All features are available.
No billing is required for self-hosted instances. All features are
available.
</p>
</CardContent>
</Card>
Expand Down
Loading
Loading