Skip to content

Commit d36c526

Browse files
committed
Fixed header navigation; Refactored default page template as per the classic theme; Email form removed from shared widget
1 parent 13322b1 commit d36c526

File tree

18 files changed

+506
-794
lines changed

18 files changed

+506
-794
lines changed

apps/web/app/(with-contexts)/(with-layout)/home-page-layout.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,15 @@ export default function HomepageLayout({
4949
siteinfo,
5050
address: address,
5151
profile: profile as Profile,
52-
auth: {
53-
guest: profile ? false : true,
54-
checked: profile ? true : false,
55-
},
52+
auth: profile.email
53+
? {
54+
guest: false,
55+
checked: true,
56+
}
57+
: {
58+
guest: true,
59+
checked: true,
60+
},
5661
networkAction: false,
5762
theme,
5863
typefaces,
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
"use client";
2+
3+
import { ThemeContext } from "@components/contexts";
4+
import {
5+
Button,
6+
Caption,
7+
Input,
8+
Section,
9+
Text1,
10+
Text2,
11+
Link as PageLink,
12+
} from "@courselit/page-primitives";
13+
import { useContext, useState } from "react";
14+
import { FormEvent } from "react";
15+
import { signIn } from "next-auth/react";
16+
import {
17+
Form,
18+
// FormField,
19+
// FormSubmit,
20+
useToast,
21+
} from "@courselit/components-library";
22+
import {
23+
BTN_LOGIN,
24+
BTN_LOGIN_GET_CODE,
25+
BTN_LOGIN_CODE_INTIMATION,
26+
LOGIN_NO_CODE,
27+
BTN_LOGIN_NO_CODE,
28+
LOGIN_FORM_LABEL,
29+
LOGIN_FORM_DISCLAIMER,
30+
LOADING,
31+
LOGIN_SUCCESS,
32+
TOAST_TITLE_ERROR,
33+
TOAST_TITLE_SUCCESS,
34+
} from "@/ui-config/strings";
35+
import Link from "next/link";
36+
import { TriangleAlert } from "lucide-react";
37+
38+
export default function LoginForm() {
39+
const { theme } = useContext(ThemeContext);
40+
const [showCode, setShowCode] = useState(false);
41+
const [email, setEmail] = useState("");
42+
const [code, setCode] = useState("");
43+
const [error, setError] = useState("");
44+
const [loading, setLoading] = useState(false);
45+
const { toast } = useToast();
46+
47+
const requestCode = async function (e: FormEvent) {
48+
e.preventDefault();
49+
const url = `/api/auth/code/generate?email=${encodeURIComponent(
50+
email,
51+
)}`;
52+
try {
53+
setLoading(true);
54+
const response = await fetch(url);
55+
const resp = await response.json();
56+
if (response.ok) {
57+
setShowCode(true);
58+
} else {
59+
toast({
60+
title: TOAST_TITLE_ERROR,
61+
description: resp.error,
62+
variant: "destructive",
63+
});
64+
}
65+
} finally {
66+
setLoading(false);
67+
}
68+
};
69+
70+
const signInUser = async function (e: FormEvent) {
71+
e.preventDefault();
72+
try {
73+
setLoading(true);
74+
const response = await signIn("credentials", {
75+
email,
76+
code,
77+
redirect: false,
78+
});
79+
if (response?.error) {
80+
setError(`Can't sign you in at this time`);
81+
} else {
82+
toast({
83+
title: TOAST_TITLE_SUCCESS,
84+
description: LOGIN_SUCCESS,
85+
});
86+
}
87+
} finally {
88+
setLoading(false);
89+
}
90+
};
91+
92+
return (
93+
<Section theme={theme.theme}>
94+
<div className="flex flex-col gap-4 min-h-[80vh]">
95+
<div className="flex justify-center grow items-center px-4 mx-auto lg:max-w-[1200px] w-full">
96+
<div className="flex flex-col">
97+
{error && (
98+
<div
99+
style={{
100+
color: theme?.theme?.colors?.error,
101+
}}
102+
className="flex items-center gap-2 mb-4"
103+
>
104+
<TriangleAlert className="w-4 h-4" />
105+
<div>
106+
<Text1 theme={theme.theme}>{error}</Text1>
107+
</div>
108+
</div>
109+
)}
110+
{!showCode && (
111+
<div>
112+
<Text1 theme={theme.theme} className="mb-4">
113+
{LOGIN_FORM_LABEL}
114+
</Text1>
115+
<Form
116+
onSubmit={requestCode}
117+
className="flex flex-col gap-4"
118+
>
119+
<Input
120+
type="email"
121+
value={email}
122+
placeholder="Enter your email"
123+
required={true}
124+
onChange={(e) =>
125+
setEmail(e.target.value)
126+
}
127+
theme={theme.theme}
128+
/>
129+
130+
<Caption
131+
theme={theme.theme}
132+
className="text-center"
133+
>
134+
{LOGIN_FORM_DISCLAIMER}
135+
<Link href="/p/terms">
136+
<span className="underline">
137+
Terms
138+
</span>
139+
</Link>
140+
</Caption>
141+
<div className="flex justify-center">
142+
{/* <FormSubmit
143+
text={
144+
loading
145+
? LOADING
146+
: BTN_LOGIN_GET_CODE
147+
}
148+
disabled={loading}
149+
/> */}
150+
<Button
151+
theme={theme.theme}
152+
disabled={loading}
153+
>
154+
{loading
155+
? LOADING
156+
: BTN_LOGIN_GET_CODE}
157+
</Button>
158+
</div>
159+
</Form>
160+
</div>
161+
)}
162+
{showCode && (
163+
<div>
164+
<Text1 theme={theme.theme} className="mb-4">
165+
{BTN_LOGIN_CODE_INTIMATION}{" "}
166+
<strong>{email}</strong>
167+
</Text1>
168+
<Form
169+
className="flex flex-col gap-4 mb-4"
170+
onSubmit={signInUser}
171+
>
172+
<Input
173+
type="text"
174+
value={code}
175+
placeholder="Code"
176+
required={true}
177+
onChange={(e) =>
178+
setCode(e.target.value)
179+
}
180+
theme={theme.theme}
181+
/>
182+
<div className="flex justify-center">
183+
{/* <FormSubmit
184+
text={loading ? LOADING : BTN_LOGIN}
185+
disabled={loading}
186+
/> */}
187+
<Button
188+
theme={theme.theme}
189+
disabled={loading}
190+
>
191+
{loading ? LOADING : BTN_LOGIN}
192+
</Button>
193+
</div>
194+
</Form>
195+
<div className="flex justify-center items-center gap-1 text-sm">
196+
<Text2
197+
theme={theme.theme}
198+
className="text-slate-500"
199+
>
200+
{LOGIN_NO_CODE}
201+
</Text2>
202+
<button
203+
onClick={requestCode}
204+
className="underline"
205+
disabled={loading}
206+
>
207+
<PageLink theme={theme.theme}>
208+
{loading
209+
? LOADING
210+
: BTN_LOGIN_NO_CODE}
211+
</PageLink>
212+
</button>
213+
</div>
214+
</div>
215+
)}
216+
</div>
217+
</div>
218+
</div>
219+
</Section>
220+
);
221+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { auth } from "@/auth";
2+
import { redirect } from "next/navigation";
3+
import LoginForm from "./login-form";
4+
5+
export default async function LoginPage({
6+
searchParams,
7+
}: {
8+
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
9+
}) {
10+
const session = await auth();
11+
const redirectTo = (await searchParams).redirect;
12+
13+
if (session) {
14+
redirect(
15+
typeof redirectTo === "string"
16+
? redirectTo
17+
: "/dashboard/my-content",
18+
);
19+
}
20+
21+
return <LoginForm />;
22+
}

apps/web/app/(with-contexts)/dashboard/page/[id]/page.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,15 @@ export default function Page({ params }: { params: { id: string } }) {
4343
siteinfo: siteInfo,
4444
address: address,
4545
profile: profile as Profile,
46-
auth: {
47-
guest: profile ? false : true,
48-
checked: profile ? true : false,
49-
},
46+
auth: profile.email
47+
? {
48+
guest: false,
49+
checked: true,
50+
}
51+
: {
52+
guest: true,
53+
checked: true,
54+
},
5055
networkAction: false,
5156
theme,
5257
typefaces: [

apps/web/app/verify-domain/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { headers } from "next/headers";
77
import connectToDatabase from "../../services/db";
88
import { warn } from "@/services/logger";
99

10-
const { domainNameForSingleTenancy } = constants;
10+
const { domainNameForSingleTenancy, schoolNameForSingleTenancy } = constants;
1111

1212
const getDomainBasedOnSubdomain = async (
1313
subdomain: string,
@@ -142,6 +142,9 @@ export async function GET(req: Request) {
142142
lastMonthlyCountUpdate: new Date(),
143143
},
144144
},
145+
settings: {
146+
title: schoolNameForSingleTenancy,
147+
},
145148
},
146149
{
147150
upsert: true,

apps/web/components/public/base-layout/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
import type { Media, Typeface, WidgetInstance } from "@courselit/common-models";
1111
import { useSession } from "next-auth/react";
1212
import { useEffect } from "react";
13-
import { UITheme } from "@models/UITheme";
13+
import { Theme } from "@courselit/page-models";
1414

1515
interface MasterLayoutProps {
1616
title: string;
@@ -25,7 +25,7 @@ interface MasterLayoutProps {
2525
socialImage?: Media;
2626
robotsAllowed?: boolean;
2727
state: AppState;
28-
theme: Omit<UITheme, "draftTheme">;
28+
theme: Theme;
2929
}
3030

3131
export const MasterLayout = ({

0 commit comments

Comments
 (0)