/
login.tsx
148 lines (136 loc) · 3.67 KB
/
login.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { useMemo } from 'react';
import {
loginUser,
setAuthSession,
} from '~/api/supabase-auth.server';
import AuthProviderBtn from '~/components/AuthProviderBtn';
import authenticated from '~/policies/authenticated.server';
import { authCookie } from '~/services/supabase.server';
import type {
ActionFunction,
LoaderFunction,
MetaFunction,
} from '@remix-run/node';
import {
json,
redirect,
} from '@remix-run/node';
import {
Form,
Link,
useActionData,
useSearchParams,
} from '@remix-run/react';
export const meta: MetaFunction = () => {
return { title: "Supabase x Remix | Login" };
};
type LoaderData = {};
export const loader: LoaderFunction = async ({ request }) => {
return authenticated(
request,
() => {
return redirect("/profile");
},
() => {
return json<LoaderData>({});
}
);
};
type ActionData = {
formError?: string;
fields?: { email: string };
};
export const action: ActionFunction = async ({ request }) => {
let session = await authCookie.getSession(request.headers.get("Cookie"));
const form = await request.formData();
const email = form.get("email");
const password = form.get("password");
const redirectTo = form.get("redirectTo") || "/profile";
if (
!email ||
!password ||
typeof redirectTo !== "string" ||
typeof email !== "string" ||
typeof password !== "string"
) {
return json<ActionData>(
{
formError: `Form not submitted correctly.`,
fields: {
email: String(email) ?? "",
},
},
403
);
}
const { accessToken, refreshToken, error } = await loginUser({
email,
password,
});
if (error || !accessToken || !refreshToken) {
return json<ActionData>(
{ formError: error || "Something went wrong", fields: { email } },
403
);
}
session = setAuthSession(session, accessToken, refreshToken);
return redirect(redirectTo, {
headers: {
"Set-Cookie": await authCookie.commitSession(session),
},
});
};
export default function Login() {
const actionData = useActionData<ActionData>();
const [searchParams] = useSearchParams();
const redirectTo = useMemo(
() => searchParams.get("redirectTo") ?? "/profile",
[searchParams]
);
return (
<div>
<h1>Login</h1>
<div style={{ margin: 5 }}>
<AuthProviderBtn provider="google" redirectTo={redirectTo} />
</div>
<div style={{ margin: 5 }}>
<AuthProviderBtn provider="facebook" redirectTo={redirectTo} />
</div>
<p>Or continue with email/password</p>
<Form replace method="post">
<input type="hidden" name="redirectTo" value={redirectTo} />
<fieldset>
<legend>Login</legend>
<div style={{ margin: 5 }}>
<label>
Email{" "}
<input
type="email"
name="email"
defaultValue={actionData?.fields?.email}
required
/>
</label>
</div>
<div style={{ margin: 5 }}>
<label>
Password <input type="password" minLength={8} name="password" required />
</label>
</div>
<div style={{ margin: 5 }}>
<Link to={`/forgot-password?redirectTo=${redirectTo}`}>Forgot password?</Link>
</div>
<div style={{ margin: 5 }}>
<button type="submit">Login</button>
</div>
</fieldset>
</Form>
<p>
Don't have an account yet? <Link to="/register">Register</Link> instead
</p>
{actionData?.formError ? (
<p style={{ color: "red" }}>{actionData.formError}</p>
) : null}
</div>
);
}