boring stuff

This commit is contained in:
m5r 2021-08-01 11:05:40 +08:00
parent cd83f0c78e
commit a65d6e2bcc
17 changed files with 261 additions and 206 deletions

View File

@ -52,7 +52,7 @@ export const LoginForm = (props: LoginFormProps) => {
</Form> </Form>
<div style={{ marginTop: "1rem" }}> <div style={{ marginTop: "1rem" }}>
Or <Link href={Routes.SignupPage()}>Sign Up</Link> Or <Link href={Routes.SignUp()}>Sign Up</Link>
</div> </div>
</div> </div>
); );

View File

@ -1,4 +1,5 @@
import { BlitzPage, useMutation } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes, useMutation } from "blitz";
import BaseLayout from "../../core/layouts/base-layout"; import BaseLayout from "../../core/layouts/base-layout";
import { LabeledTextField } from "../../core/components/labeled-text-field"; import { LabeledTextField } from "../../core/components/labeled-text-field";
@ -44,7 +45,8 @@ const ForgotPasswordPage: BlitzPage = () => {
); );
}; };
ForgotPasswordPage.redirectAuthenticatedTo = "/"; ForgotPasswordPage.redirectAuthenticatedTo = Routes.Messages();
ForgotPasswordPage.getLayout = (page) => ( ForgotPasswordPage.getLayout = (page) => (
<BaseLayout title="Forgot Your Password?">{page}</BaseLayout> <BaseLayout title="Forgot Your Password?">{page}</BaseLayout>
); );

View File

@ -1,4 +1,5 @@
import { BlitzPage, useRouterQuery, Link, useMutation, Routes } from "blitz"; import type { BlitzPage } from "blitz";
import { useRouterQuery, Link, useMutation, Routes } from "blitz";
import BaseLayout from "../../core/layouts/base-layout"; import BaseLayout from "../../core/layouts/base-layout";
import { LabeledTextField } from "../../core/components/labeled-text-field"; import { LabeledTextField } from "../../core/components/labeled-text-field";
@ -59,7 +60,8 @@ const ResetPasswordPage: BlitzPage = () => {
); );
}; };
ResetPasswordPage.redirectAuthenticatedTo = "/"; ResetPasswordPage.redirectAuthenticatedTo = Routes.Messages();
ResetPasswordPage.getLayout = (page) => <BaseLayout title="Reset Your Password">{page}</BaseLayout>; ResetPasswordPage.getLayout = (page) => <BaseLayout title="Reset Your Password">{page}</BaseLayout>;
export default ResetPasswordPage; export default ResetPasswordPage;

View File

@ -1,9 +1,10 @@
import { useRouter, BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { useRouter, Routes } from "blitz";
import BaseLayout from "../../core/layouts/base-layout"; import BaseLayout from "../../core/layouts/base-layout";
import { LoginForm } from "../components/login-form"; import { LoginForm } from "../components/login-form";
const LoginPage: BlitzPage = () => { const SignIn: BlitzPage = () => {
const router = useRouter(); const router = useRouter();
return ( return (
@ -12,7 +13,7 @@ const LoginPage: BlitzPage = () => {
onSuccess={() => { onSuccess={() => {
const next = router.query.next const next = router.query.next
? decodeURIComponent(router.query.next as string) ? decodeURIComponent(router.query.next as string)
: "/"; : Routes.Messages();
router.push(next); router.push(next);
}} }}
/> />
@ -20,7 +21,8 @@ const LoginPage: BlitzPage = () => {
); );
}; };
LoginPage.redirectAuthenticatedTo = "/"; SignIn.redirectAuthenticatedTo = Routes.Messages();
LoginPage.getLayout = (page) => <BaseLayout title="Log In">{page}</BaseLayout>;
export default LoginPage; SignIn.getLayout = (page) => <BaseLayout title="Sign In">{page}</BaseLayout>;
export default SignIn;

View File

@ -1,19 +1,21 @@
import { useRouter, BlitzPage, Routes } from "blitz"; import type { BlitzPage } from "blitz";
import { useRouter, Routes } from "blitz";
import BaseLayout from "../../core/layouts/base-layout"; import BaseLayout from "../../core/layouts/base-layout";
import { SignupForm } from "../components/signup-form"; import { SignupForm } from "../components/signup-form";
const SignupPage: BlitzPage = () => { const SignUp: BlitzPage = () => {
const router = useRouter(); const router = useRouter();
return ( return (
<div> <div>
<SignupForm onSuccess={() => router.push(Routes.Home())} /> <SignupForm onSuccess={() => router.push(Routes.StepOne())} />
</div> </div>
); );
}; };
SignupPage.redirectAuthenticatedTo = "/"; SignUp.redirectAuthenticatedTo = Routes.StepOne();
SignupPage.getLayout = (page) => <BaseLayout title="Sign Up">{page}</BaseLayout>;
export default SignupPage; SignUp.getLayout = (page) => <BaseLayout title="Sign Up">{page}</BaseLayout>;
export default SignUp;

View File

@ -1,4 +1,5 @@
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import type { FunctionComponent } from "react"; import type { FunctionComponent } from "react";
import { atom, useAtom } from "jotai"; import { atom, useAtom } from "jotai";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -7,15 +8,12 @@ import { faBackspace, faPhoneAlt as faPhone } from "@fortawesome/pro-solid-svg-i
import Layout from "../../core/layouts/layout"; import Layout from "../../core/layouts/layout";
import useRequireOnboarding from "../../core/hooks/use-require-onboarding"; import useRequireOnboarding from "../../core/hooks/use-require-onboarding";
const pageTitle = "Keypad";
const Keypad: BlitzPage = () => { const Keypad: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
const phoneNumber = useAtom(phoneNumberAtom)[0]; const phoneNumber = useAtom(phoneNumberAtom)[0];
const pressBackspace = useAtom(pressBackspaceAtom)[1]; const pressBackspace = useAtom(pressBackspaceAtom)[1];
return ( return (
<Layout title={pageTitle}>
<div className="w-96 h-full flex flex-col justify-around py-5 mx-auto text-center text-black bg-white"> <div className="w-96 h-full flex flex-col justify-around py-5 mx-auto text-center text-black bg-white">
<div className="h-16 text-3xl text-gray-700"> <div className="h-16 text-3xl text-gray-700">
<span>{phoneNumber}</span> <span>{phoneNumber}</span>
@ -62,16 +60,12 @@ const Keypad: BlitzPage = () => {
<div className="cursor-pointer select-none col-start-2 h-12 w-12 flex justify-center items-center mx-auto bg-green-800 rounded-full"> <div className="cursor-pointer select-none col-start-2 h-12 w-12 flex justify-center items-center mx-auto bg-green-800 rounded-full">
<FontAwesomeIcon icon={faPhone} color="white" size="lg" /> <FontAwesomeIcon icon={faPhone} color="white" size="lg" />
</div> </div>
<div <div className="cursor-pointer select-none my-auto" onClick={pressBackspace}>
className="cursor-pointer select-none my-auto"
onClick={pressBackspace}
>
<FontAwesomeIcon icon={faBackspace} size="lg" /> <FontAwesomeIcon icon={faBackspace} size="lg" />
</div> </div>
</Row> </Row>
</section> </section>
</div> </div>
</Layout>
); );
}; };
@ -123,4 +117,8 @@ const pressBackspaceAtom = atom(null, (get, set) => {
set(phoneNumberAtom, (prevState) => prevState.slice(0, -1)); set(phoneNumberAtom, (prevState) => prevState.slice(0, -1));
}); });
Keypad.getLayout = (page) => <Layout title="Keypad">{page}</Layout>;
Keypad.authenticate = { redirectTo: Routes.SignIn() };
export default Keypad; export default Keypad;

View File

@ -1,4 +1,4 @@
import { Link, useQuery } from "blitz"; import { Link, useQuery, Routes } from "blitz";
import getConversationsQuery from "../queries/get-conversations"; import getConversationsQuery from "../queries/get-conversations";
@ -15,7 +15,11 @@ export default function ConversationsList() {
const lastMessage = messages[messages.length - 1]!; const lastMessage = messages[messages.length - 1]!;
return ( return (
<li key={recipient} className="py-2"> <li key={recipient} className="py-2">
<Link href={`/messages/${encodeURIComponent(recipient)}`}> <Link
href={Routes.ConversationPage({
recipient: encodeURIComponent(recipient),
})}
>
<a className="flex flex-col"> <a className="flex flex-col">
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<strong>{recipient}</strong> <strong>{recipient}</strong>

View File

@ -1,5 +1,6 @@
import { Suspense } from "react"; import { Suspense } from "react";
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import Layout from "../../core/layouts/layout"; import Layout from "../../core/layouts/layout";
import ConversationsList from "../components/conversations-list"; import ConversationsList from "../components/conversations-list";
@ -9,17 +10,19 @@ const Messages: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
return ( return (
<Layout title="Messages"> <>
<div className="flex flex-col space-y-6 p-6"> <div className="flex flex-col space-y-6 p-6">
<p>Messages page</p> <p>Messages page</p>
</div> </div>
<Suspense fallback="Loading..."> <Suspense fallback="Loading...">
<ConversationsList /> <ConversationsList />
</Suspense> </Suspense>
</Layout> </>
); );
}; };
Messages.authenticate = true; Messages.getLayout = (page) => <Layout title="Messages">{page}</Layout>;
Messages.authenticate = { redirectTo: Routes.SignIn() };
export default Messages; export default Messages;

View File

@ -1,5 +1,6 @@
import { Suspense } from "react"; import { Suspense } from "react";
import { BlitzPage, useRouter } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes, useRouter } from "blitz";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import {
faLongArrowLeft, faLongArrowLeft,
@ -16,10 +17,9 @@ const ConversationPage: BlitzPage = () => {
const router = useRouter(); const router = useRouter();
const recipient = router.params.recipient; const recipient = router.params.recipient;
const pageTitle = `Messages with ${recipient}`;
return ( return (
<Layout title={pageTitle} hideFooter> <>
<header className="absolute top-0 w-screen h-12 backdrop-filter backdrop-blur-sm bg-white bg-opacity-75 border-b grid grid-cols-3 items-center"> <header className="absolute top-0 w-screen h-12 backdrop-filter backdrop-blur-sm bg-white bg-opacity-75 border-b grid grid-cols-3 items-center">
<span className="col-start-1 col-span-1 pl-2 cursor-pointer" onClick={router.back}> <span className="col-start-1 col-span-1 pl-2 cursor-pointer" onClick={router.back}>
<FontAwesomeIcon size="lg" className="h-8 w-8" icon={faLongArrowLeft} /> <FontAwesomeIcon size="lg" className="h-8 w-8" icon={faLongArrowLeft} />
@ -33,10 +33,22 @@ const ConversationPage: BlitzPage = () => {
<Suspense fallback={<div className="pt-12">Loading messages with {recipient}</div>}> <Suspense fallback={<div className="pt-12">Loading messages with {recipient}</div>}>
<Conversation /> <Conversation />
</Suspense> </Suspense>
</>
);
};
ConversationPage.getLayout = function ConversationLayout(page) {
const router = useRouter();
const recipient = router.params.recipient;
const pageTitle = `Messages with ${recipient}`;
return (
<Layout title={pageTitle} hideFooter>
{page}
</Layout> </Layout>
); );
}; };
ConversationPage.authenticate = true; ConversationPage.authenticate = { redirectTo: Routes.SignIn() };
export default ConversationPage; export default ConversationPage;

View File

@ -9,18 +9,22 @@ const StepOne: BlitzPage = () => {
useCurrentCustomer(); // preload for step two useCurrentCustomer(); // preload for step two
return ( return (
<OnboardingLayout
currentStep={1}
next={{ href: "/welcome/step-two", label: "Set up your phone number" }}
>
<div className="flex flex-col space-y-4 items-center"> <div className="flex flex-col space-y-4 items-center">
<span>Welcome, lets set up your virtual phone!</span> <span>Welcome, lets set up your virtual phone!</span>
</div> </div>
</OnboardingLayout>
); );
}; };
StepOne.authenticate = true; StepOne.getLayout = (page) => (
<OnboardingLayout
currentStep={1}
next={{ href: Routes.StepTwo().pathname, label: "Set up your phone number" }}
>
{page}
</OnboardingLayout>
);
StepOne.authenticate = { redirectTo: Routes.SignIn() };
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => { export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const session = await getSession(req, res); const session = await getSession(req, res);

View File

@ -48,13 +48,9 @@ const StepThree: BlitzPage<Props> = ({ availablePhoneNumbers }) => {
}); });
return ( return (
<OnboardingLayout currentStep={3} previous={{ href: "/welcome/step-two", label: "Back" }}>
<div className="flex flex-col space-y-4 items-center"> <div className="flex flex-col space-y-4 items-center">
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<label <label htmlFor="phoneNumberSid" className="block text-sm font-medium text-gray-700">
htmlFor="phoneNumberSid"
className="block text-sm font-medium text-gray-700"
>
Phone number Phone number
</label> </label>
<select <select
@ -81,11 +77,16 @@ const StepThree: BlitzPage<Props> = ({ availablePhoneNumbers }) => {
</button> </button>
</form> </form>
</div> </div>
</OnboardingLayout>
); );
}; };
StepThree.authenticate = true; StepThree.getLayout = (page) => (
<OnboardingLayout currentStep={3} previous={{ href: Routes.StepTwo().pathname, label: "Back" }}>
{page}
</OnboardingLayout>
);
StepThree.authenticate = { redirectTo: Routes.SignIn() };
export const getServerSideProps: GetServerSideProps<Props> = async ({ req, res }) => { export const getServerSideProps: GetServerSideProps<Props> = async ({ req, res }) => {
const session = await getSession(req, res); const session = await getSession(req, res);

View File

@ -25,13 +25,10 @@ const StepTwo: BlitzPage = () => {
const { customer } = useCurrentCustomer(); const { customer } = useCurrentCustomer();
const [setTwilioApiFieldsMutation] = useMutation(setTwilioApiFields); const [setTwilioApiFieldsMutation] = useMutation(setTwilioApiFields);
const initialAuthToken = customer?.authToken ?? "";
const initialAccountSid = customer?.accountSid ?? "";
const hasTwilioCredentials = initialAccountSid.length > 0 && initialAuthToken.length > 0;
useEffect(() => { useEffect(() => {
setValue("twilioAuthToken", initialAuthToken); setValue("twilioAuthToken", customer?.authToken ?? "");
setValue("twilioAccountSid", initialAccountSid); setValue("twilioAccountSid", customer?.accountSid ?? "");
}, [initialAuthToken, initialAccountSid]); }, [setValue, customer?.authToken, customer?.accountSid]);
const onSubmit = handleSubmit(async ({ twilioAccountSid, twilioAuthToken }) => { const onSubmit = handleSubmit(async ({ twilioAccountSid, twilioAuthToken }) => {
if (isSubmitting) { if (isSubmitting) {
@ -47,11 +44,6 @@ const StepTwo: BlitzPage = () => {
}); });
return ( return (
<OnboardingLayout
currentStep={2}
next={hasTwilioCredentials ? { href: "/welcome/step-three", label: "Next" } : undefined}
previous={{ href: "/welcome/step-one", label: "Back" }}
>
<div className="flex flex-col space-y-4 items-center"> <div className="flex flex-col space-y-4 items-center">
<form onSubmit={onSubmit} className="flex flex-col gap-6"> <form onSubmit={onSubmit} className="flex flex-col gap-6">
<div className="w-full"> <div className="w-full">
@ -95,11 +87,31 @@ const StepTwo: BlitzPage = () => {
</button> </button>
</form> </form>
</div> </div>
);
};
StepTwo.getLayout = function StepTwoLayout(page) {
const { customer } = useCurrentCustomer();
const initialAuthToken = customer?.authToken ?? "";
const initialAccountSid = customer?.accountSid ?? "";
const hasTwilioCredentials = initialAccountSid.length > 0 && initialAuthToken.length > 0;
return (
<OnboardingLayout
currentStep={2}
next={
hasTwilioCredentials
? { href: Routes.StepThree().pathname, label: "Next" }
: undefined
}
previous={{ href: Routes.StepOne().pathname, label: "Back" }}
>
{page}
</OnboardingLayout> </OnboardingLayout>
); );
}; };
StepTwo.authenticate = true; StepTwo.authenticate = { redirectTo: Routes.SignIn() };
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => { export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const session = await getSession(req, res); const session = await getSession(req, res);

View File

@ -1,5 +1,6 @@
import { Suspense } from "react"; import { Suspense } from "react";
import { Link, BlitzPage, useMutation, Routes } from "blitz"; import type { BlitzPage } from "blitz";
import { Link, useMutation, Routes } from "blitz";
import BaseLayout from "../core/layouts/base-layout"; import BaseLayout from "../core/layouts/base-layout";
import logout from "../auth/mutations/logout"; import logout from "../auth/mutations/logout";
@ -35,12 +36,12 @@ const UserInfo = () => {
} else { } else {
return ( return (
<> <>
<Link href={Routes.SignupPage()}> <Link href={Routes.SignUp()}>
<a className="button small"> <a className="button small">
<strong>Sign Up</strong> <strong>Sign Up</strong>
</a> </a>
</Link> </Link>
<Link href={Routes.LoginPage()}> <Link href={Routes.SignIn()}>
<a className="button small"> <a className="button small">
<strong>Login</strong> <strong>Login</strong>
</a> </a>
@ -268,6 +269,7 @@ const Home: BlitzPage = () => {
}; };
Home.suppressFirstRenderFlicker = true; Home.suppressFirstRenderFlicker = true;
Home.getLayout = (page) => <BaseLayout title="Home">{page}</BaseLayout>; Home.getLayout = (page) => <BaseLayout title="Home">{page}</BaseLayout>;
export default Home; export default Home;

View File

@ -1,5 +1,6 @@
import { Suspense } from "react"; import { Suspense } from "react";
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import Layout from "../../core/layouts/layout"; import Layout from "../../core/layouts/layout";
import PhoneCallsList from "../components/phone-calls-list"; import PhoneCallsList from "../components/phone-calls-list";
@ -9,17 +10,19 @@ const PhoneCalls: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
return ( return (
<Layout title="Calls"> <>
<div className="flex flex-col space-y-6 p-6"> <div className="flex flex-col space-y-6 p-6">
<p>Calls page</p> <p>Calls page</p>
</div> </div>
<Suspense fallback="Loading..."> <Suspense fallback="Loading...">
<PhoneCallsList /> <PhoneCallsList />
</Suspense> </Suspense>
</Layout> </>
); );
}; };
PhoneCalls.authenticate = true; PhoneCalls.getLayout = (page) => <Layout title="Calls">{page}</Layout>;
PhoneCalls.authenticate = { redirectTo: Routes.SignIn() };
export default PhoneCalls; export default PhoneCalls;

View File

@ -1,4 +1,5 @@
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCreditCard, faUserCircle } from "@fortawesome/pro-regular-svg-icons"; import { faCreditCard, faUserCircle } from "@fortawesome/pro-regular-svg-icons";
@ -32,7 +33,6 @@ const Settings: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
return ( return (
<Layout title="Settings">
<div className="flex flex-col space-y-6 p-6"> <div className="flex flex-col space-y-6 p-6">
<aside className="py-6 lg:col-span-3"> <aside className="py-6 lg:col-span-3">
<nav className="space-y-1"> <nav className="space-y-1">
@ -49,10 +49,11 @@ const Settings: BlitzPage = () => {
</nav> </nav>
</aside> </aside>
</div> </div>
</Layout>
); );
}; };
Settings.authenticate = true; Settings.getLayout = (page) => <Layout title="Settings">{page}</Layout>;
Settings.authenticate = { redirectTo: Routes.SignIn() };
export default Settings; export default Settings;

View File

@ -1,4 +1,5 @@
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import SettingsLayout from "../../components/settings-layout"; import SettingsLayout from "../../components/settings-layout";
import ProfileInformations from "../../components/profile-informations"; import ProfileInformations from "../../components/profile-informations";
@ -31,6 +32,8 @@ const Account: BlitzPage = () => {
); );
}; };
Account.authenticate = true; Account.getLayout = (page) => <SettingsLayout>{page}</SettingsLayout>;
Account.authenticate = { redirectTo: Routes.SignIn() };
export default Account; export default Account;

View File

@ -111,10 +111,12 @@ export const getServerSideProps = withPageOnboardingRequired<Props>(
*/ */
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz";
import { useRouter } from "blitz"; import { useRouter } from "blitz";
import { useEffect } from "react"; import { useEffect } from "react";
import useRequireOnboarding from "../../../core/hooks/use-require-onboarding"; import useRequireOnboarding from "../../../core/hooks/use-require-onboarding";
import SettingsLayout from "../../components/settings-layout";
const Billing: BlitzPage = () => { const Billing: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
@ -127,6 +129,8 @@ const Billing: BlitzPage = () => {
return null; return null;
}; };
Billing.authenticate = true; Billing.getLayout = (page) => <SettingsLayout>{page}</SettingsLayout>;
Billing.authenticate = { redirectTo: Routes.SignIn() };
export default Billing; export default Billing;