Created
August 6, 2023 19:26
-
-
Save daguitosama/5e4785a1eb10c1bcba46bced365d12c0 to your computer and use it in GitHub Desktop.
Wix User Auth Contenxt Layer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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