Skip to content

Instantly share code, notes, and snippets.

@daguitosama
Created August 6, 2023 19:26
Show Gist options
  • Save daguitosama/5e4785a1eb10c1bcba46bced365d12c0 to your computer and use it in GitHub Desktop.
Save daguitosama/5e4785a1eb10c1bcba46bced365d12c0 to your computer and use it in GitHub Desktop.
Wix User Auth Contenxt Layer
import {
Outlet,
isRouteErrorResponse,
useLoaderData,
useOutletContext,
useRouteError
} from "@remix-run/react";
import { createClient, LoginState, OAuthStrategy, Tokens, WixClient } from "@wix/api-client";
import type { LoaderArgs } from "@remix-run/server-runtime";
import { json } from "@remix-run/cloudflare";
type LoginResult = { success: { tokens: Tokens } | null; error: null | string };
type AccountContext = {
client: WixClient | null;
login: ((email: string, password: string) => Promise<LoginResult>) | null;
register:
| ((
first_name: string,
last_name: string,
email: string,
password: string
) => Promise<LoginResult>)
| null;
continue_registration_with_code: ((code: string) => Promise<LoginResult>) | null;
logout: () => Promise<void>;
};
type LoaderData = {
client_id: string;
origin: string;
};
export async function loader({ request, context }: LoaderArgs) {
return json<LoaderData>({
client_id: context.WIX_APP_CLIENT_ID,
origin: new URL(request.url).origin
});
}
export default function AccountLayout() {
const loaderData = useLoaderData<LoaderData>();
if (typeof loaderData.client_id != "string") {
throw new Error("Non valid CLIENT_ID found at wix client initialization");
}
var client = createClient({
auth: OAuthStrategy({ clientId: loaderData.client_id }),
modules: {}
});
var login = create_login(client);
var register = create_register(client);
var continue_registration_with_code = create_continue_registration_with_code(client);
async function logout() {
console.log("origin received as:", loaderData.origin);
const { logoutUrl } = await client.auth.logout(
loaderData.origin + "/account/logout_post_flow"
);
window.location.href = logoutUrl;
}
return (
<div className="">
<Outlet
context={
{
client,
login,
register,
continue_registration_with_code,
logout
} satisfies AccountContext
}
/>
</div>
);
}
export function useAccount() {
return useOutletContext<AccountContext>();
}
export function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return (
<div className="px-[30px] py-[40px]">
<h1 className="text-3xl">Something bad happen</h1>
<p className="mt-[40px]">
If you are seeing this, please, let us know at{" "}
<a href="mailto:techsupport@damanci.com" className="text-blue-700 underline">
techsupport@damanci.com
</a>
. We really sorry for the inconvenience. While we fix this, you can browse our{" "}
<a href="/shop" className="text-blue-700 underline">
collections
</a>
</p>
<details className="mt-[30px] border border-red-600 bg-red-200 p-4 rounded-xl overflow-auto">
<summary>Error Details</summary>
<pre>
<code className="block">Status: {error.status}</code>
<code className="block">Status text: {error.statusText}</code>
<code className="block">Data: {error.data}</code>
</pre>
</details>
</div>
);
} else if (error instanceof Error) {
return (
<div className="px-[30px] py-[40px]">
<h1 className="text-3xl">Something bad happen</h1>
<p className="mt-[40px]">
If you are seeing this, please, let us know at{" "}
<a href="mailto:techsupport@damanci.com" className="text-blue-700 underline">
techsupport@damanci.com
</a>
. We really sorry for the inconvenience. While we fix this, you can browse our{" "}
<a href="/shop" className="text-blue-700 underline">
collections
</a>
</p>
<details className="mt-[30px] border border-red-600 bg-red-200 p-4 rounded-xl overflow-auto">
<summary>Error Details</summary>
<pre>
<code>{error.name}</code>
<code>{error.message}</code>
<code>{error.stack}</code>
</pre>
</details>
</div>
);
} else {
return <h1>Unknown Error</h1>;
}
}
// helpers
function create_login(client: WixClient): AccountContext["login"] {
return async function login(email: string, password: string) {
var res;
// todo: learn how to signal that
// a errors imply a null result
// and viceversa
const result: LoginResult = { success: null, error: null };
try {
res = await client.auth.login({
email,
password
});
} catch (error) {
console.log("(account) wix_api.login Error: ");
console.log(error);
result.error =
"There is a technical issue right now, and we could not process your request. Please try again. If the error persist try contact us.";
}
switch (res.loginState) {
case LoginState.SUCCESS: {
break;
}
case LoginState.OWNER_APPROVAL_REQUIRED: {
result.error = "Your account is pending approval";
}
case LoginState.EMAIL_VERIFICATION_REQUIRED: {
result.error = LoginState.EMAIL_VERIFICATION_REQUIRED;
}
case LoginState.FAILURE: {
// @ts-ignore
switch (res.errorCode) {
case "invalidPassword": {
result.error =
"The email or the password, or both didn't match. Please try again";
break;
}
case "invalidEmail": {
result.error =
"The email or the password, or both didn't match. Please try again";
break;
}
case "resetPassword": {
result.error = "Your password requires reset.";
break;
}
}
break;
}
default: {
result.error = "The login API responded with an unknown response";
}
}
// success path
if (res.loginState == LoginState.SUCCESS) {
if (!(res.data && res.data.sessionToken)) {
result.error = "Non valid session Tokens came back from the api";
}
const tokens = await client.auth.getMemberTokensForDirectLogin(res.data.sessionToken);
result.success = { tokens };
}
return result;
};
}
function create_register(client: WixClient): AccountContext["register"] {
return async function register(
first_name: string,
last_name: string,
email: string,
password: string
) {
var res;
// todo: learn how to signal that
// a errors imply a null result
// and viceversa
const result: LoginResult = { success: null, error: null };
try {
res = await client.auth.register({
email,
password,
profile: {
firstName: first_name,
lastName: last_name
}
});
} catch (error) {
console.log("(account) wix_api.register Error: ");
console.log(error);
result.error =
"There is a technical issue right now, and we could not process your request. Please try again. If the error persist try contact us.";
}
console.log({ res });
switch (res.loginState) {
case LoginState.SUCCESS: {
break;
}
case LoginState.OWNER_APPROVAL_REQUIRED: {
result.error = "Your account is pending approval";
}
case LoginState.EMAIL_VERIFICATION_REQUIRED: {
result.error = LoginState.EMAIL_VERIFICATION_REQUIRED;
}
case LoginState.FAILURE: {
// @ts-ignore
switch (res.errorCode) {
case "invalidPassword": {
result.error =
"The email or the password, or both didn't match. Please try again";
break;
}
case "invalidEmail": {
result.error =
"The email or the password, or both didn't match. Please try again";
break;
}
case "resetPassword": {
result.error = "Your password requires reset.";
break;
}
case "emailAlreadyExists": {
result.error = "This email all ready exists. Try to login instead. ";
break;
}
}
break;
}
default: {
result.error = "The login API responded with an unknown response";
}
}
// success path
if (res.loginState == LoginState.SUCCESS) {
if (!(res.data && res.data.sessionToken)) {
result.error = "Non valid session Tokens came back from the api";
}
const tokens = await client.auth.getMemberTokensForDirectLogin(res.data.sessionToken);
result.success = { tokens };
}
return result;
};
}
function create_continue_registration_with_code(
client: WixClient
): AccountContext["continue_registration_with_code"] {
return async function continue_with_code(code: string) {
const response = await client.auth.processVerification({
verificationCode: code
});
const result: LoginResult = { success: null, error: null };
if (response.loginState === LoginState.SUCCESS) {
const tokens = await client.auth.getMemberTokensForDirectLogin(
response.data.sessionToken!
);
result.success = { tokens };
} else {
if (response.error) {
result.error = response.error;
} else {
result.error = "Unknown error";
}
}
console.log({ response });
return result;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment