add cms setup stubs

This commit is contained in:
Sidney Alcantara
2022-02-14 19:00:00 +11:00
parent 83c5fab773
commit 362eca3eed
4 changed files with 273 additions and 156 deletions

View File

@@ -1,25 +1,36 @@
import { ISetupStepBodyProps } from "@src/pages/Setup";
import { FormControlLabel, Checkbox, Typography, Link } from "@mui/material";
import {
FormControlLabel,
Checkbox,
Typography,
Link,
Button,
} from "@mui/material";
import { useAppContext } from "@src/contexts/AppContext";
import { EXTERNAL_LINKS } from "@src/constants/externalLinks";
export interface IStep0WelcomeProps extends ISetupStepBodyProps {
handleContinue: () => void;
}
export default function Step0Welcome({
completion,
setCompletion,
}: ISetupStepBodyProps) {
handleContinue,
}: IStep0WelcomeProps) {
const { projectId } = useAppContext();
return (
<>
<div>
<Typography variant="body1" gutterBottom>
Youll be up and running in just a few minutes.
<Typography variant="body1" paragraph>
Get started with Rowy in just a few minutes.
</Typography>
<Typography variant="body1" gutterBottom>
Configure your projects backend functionality, Firestore Rules, and
user management.
<Typography variant="body1" paragraph>
We have no access to your data and it always stays on your Firebase
project.
</Typography>
<Typography variant="body1">
Project: <b>{projectId}</b>
@@ -67,6 +78,23 @@ export default function Step0Welcome({
m: 0,
}}
/>
<Button
variant="contained"
color="primary"
size="large"
disabled={!completion.welcome}
onClick={handleContinue}
>
Get started
</Button>
<div>
<Typography variant="body2" paragraph sx={{ mt: 4 }}>
Want to invite your teammate to help with setup instead?
</Typography>
<Button>Send to teammate</Button>
</div>
</>
);
}

View File

@@ -0,0 +1,54 @@
import { ISetupStepBodyProps } from "@src/pages/Setup";
import { Typography, Link, Button } from "@mui/material";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import SetupItem from "./SetupItem";
import { WIKI_LINKS } from "@src/constants/externalLinks";
export default function Step1Oauth({
completion,
setCompletion,
}: ISetupStepBodyProps) {
return (
<>
<div>
<Typography variant="inherit" paragraph>
Allow Rowy to manage your Firebase Authentication, Firestore database,
and Firebase Storage.
</Typography>
<Typography variant="inherit">
Your data and code always stays on your Firebase project.{" "}
<Link
href={WIKI_LINKS.setup}
target="_blank"
rel="noopener noreferrer"
>
Learn more
<InlineOpenInNewIcon />
</Link>
</Typography>
</div>
<SetupItem
title="Sign in with a Google account that has access to your Firebase project."
status="incomplete"
>
<Button
startIcon={
<img
src="https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/google.svg"
alt="Google logo"
width="20"
height="20"
/>
}
onClick={() => setCompletion((c) => ({ ...c, oauth: true }))}
>
Sign in with Google
</Button>
</SetupItem>
</>
);
}

View File

@@ -0,0 +1,47 @@
import { ISetupStepBodyProps } from "@src/pages/Setup";
import {
Typography,
TextField,
MenuItem,
Divider,
Button,
} from "@mui/material";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import SetupItem from "./SetupItem";
import { WIKI_LINKS } from "@src/constants/externalLinks";
export default function Step1Oauth({
completion,
setCompletion,
}: ISetupStepBodyProps) {
return (
<>
<Typography variant="inherit">
Select which Firebase project to set up Rowy on.
</Typography>
<SetupItem
title="Select an existing project or create a new one."
status="incomplete"
>
<TextField label="Project" select style={{ minWidth: 200 }}>
<MenuItem value="lorem">lorem</MenuItem>
<MenuItem value="ipsum">ipsum</MenuItem>
<MenuItem value="dolor">dolor</MenuItem>
<MenuItem value="sit">sit</MenuItem>
<MenuItem value="amet">amet</MenuItem>
</TextField>
<Divider style={{ width: 200 }}>OR</Divider>
<Button onClick={() => setCompletion((c) => ({ ...c, project: true }))}>
Create project in Firebase Console
<InlineOpenInNewIcon />
</Button>
</SetupItem>
</>
);
}

View File

@@ -29,7 +29,8 @@ import ScrollableDialogContent from "@src/components/Modal/ScrollableDialogConte
import { SlideTransition } from "@src/components/Modal/SlideTransition";
import Step0Welcome from "@src/components/Setup/Step0Welcome";
import Step1RowyRun, { checkRowyRun } from "@src/components/Setup/Step1RowyRun";
import Step1Oauth from "@src/components/Setup/Step1Oauth";
import Step2Project from "@src/components/Setup/Step2Project";
// prettier-ignore
import Step2ProjectOwner, { checkProjectOwner } from "@src/components/Setup/Step2ProjectOwner";
import Step3Rules, { checkRules } from "@src/components/Setup/Step3Rules";
@@ -47,7 +48,6 @@ export interface ISetupStep {
title: React.ReactNode;
description?: React.ReactNode;
body: React.ReactNode;
actions?: React.ReactNode;
}
export interface ISetupStepBodyProps {
@@ -69,25 +69,25 @@ const checkAllSteps = async (
console.log("Check all steps");
const completion: Record<string, boolean> = {};
const rowyRunValidation = await checkRowyRun(rowyRunUrl, signal);
if (rowyRunValidation.isValidRowyRunUrl) {
if (rowyRunValidation.isLatestVersion) completion.rowyRun = true;
// const rowyRunValidation = await checkRowyRun(rowyRunUrl, signal);
// if (rowyRunValidation.isValidRowyRunUrl) {
// if (rowyRunValidation.isLatestVersion) completion.rowyRun = true;
const promises = [
checkProjectOwner(rowyRunUrl, currentUser, userRoles, signal).then(
(projectOwner) => {
if (projectOwner) completion.projectOwner = true;
}
),
checkRules(rowyRunUrl, authToken, signal).then((rules) => {
if (rules) completion.rules = true;
}),
checkMigrate(rowyRunUrl, authToken, signal).then((requiresMigration) => {
if (requiresMigration) completion.migrate = false;
}),
];
await Promise.all(promises);
}
// const promises = [
// checkProjectOwner(rowyRunUrl, currentUser, userRoles, signal).then(
// (projectOwner) => {
// if (projectOwner) completion.projectOwner = true;
// }
// ),
// checkRules(rowyRunUrl, authToken, signal).then((rules) => {
// if (rules) completion.rules = true;
// }),
// checkMigrate(rowyRunUrl, authToken, signal).then((requiresMigration) => {
// if (requiresMigration) completion.migrate = false;
// }),
// ];
// await Promise.all(promises);
// }
return completion;
};
@@ -111,118 +111,34 @@ export default function SetupPage() {
rules: false,
});
const [checkingAllSteps, setCheckingAllSteps] = useState(false);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
// const [checkingAllSteps, setCheckingAllSteps] = useState(false);
// useEffect(() => {
// const controller = new AbortController();
// const signal = controller.signal;
if (rowyRunUrl) {
setCheckingAllSteps(true);
getAuthToken().then((authToken) =>
checkAllSteps(
rowyRunUrl,
currentUser,
userRoles,
authToken,
signal
).then((result) => {
if (!signal.aborted) {
setCompletion((c) => ({ ...c, ...result }));
setCheckingAllSteps(false);
}
})
);
}
// if (rowyRunUrl) {
// setCheckingAllSteps(true);
// getAuthToken().then((authToken) =>
// checkAllSteps(
// rowyRunUrl,
// currentUser,
// userRoles,
// authToken,
// signal
// ).then((result) => {
// if (!signal.aborted) {
// setCompletion((c) => ({ ...c, ...result }));
// setCheckingAllSteps(false);
// }
// })
// );
// }
return () => controller.abort();
}, [rowyRunUrl, currentUser, userRoles, getAuthToken]);
// return () => controller.abort();
// }, [rowyRunUrl, currentUser, userRoles, getAuthToken]);
const stepProps = { completion, setCompletion, checkAllSteps, rowyRunUrl };
const steps: ISetupStep[] = [
{
id: "welcome",
layout: "centered" as "centered",
shortTitle: "Welcome",
title: `Welcome to Rowy`,
body: <Step0Welcome {...stepProps} />,
actions: completion.welcome ? (
<LoadingButton
loading={checkingAllSteps}
variant="contained"
color="primary"
type="submit"
>
Get started
</LoadingButton>
) : (
<Tooltip title="Please accept the terms and conditions">
<div>
<LoadingButton
loading={checkingAllSteps}
variant="contained"
color="primary"
disabled
>
Get started
</LoadingButton>
</div>
</Tooltip>
),
},
{
id: "rowyRun",
shortTitle: `Rowy Run`,
title: `Set up Rowy Run`,
body: <Step1RowyRun {...stepProps} />,
},
{
id: "projectOwner",
shortTitle: `Project owner`,
title: `Set up project owner`,
body: <Step2ProjectOwner {...stepProps} />,
},
{
id: "rules",
shortTitle: `Rules`,
title: `Set up Firestore Rules`,
body: <Step3Rules {...stepProps} />,
},
completion.migrate !== undefined
? {
id: "migrate",
shortTitle: `Migrate`,
title: `Migrate to Rowy (optional)`,
body: <Step4Migrate {...stepProps} />,
}
: ({} as ISetupStep),
{
id: "finish",
layout: "centered" as "centered",
shortTitle: `Finish`,
title: `Youre all set up!`,
body: <Step5Finish />,
actions: (
<Button
variant="contained"
color="primary"
component={Link}
to={routes.home}
sx={{ ml: 1 }}
>
Continue to Rowy
</Button>
),
},
].filter((x) => x.id);
const step =
steps.find((step) => step.id === (stepId || steps[0].id)) ?? steps[0];
const stepIndex = steps.findIndex(
(step) => step.id === (stepId || steps[0].id)
);
const listedSteps = steps.filter((step) => step.layout !== "centered");
const handleContinue = () => {
let nextIncompleteStepIndex = stepIndex + 1;
while (completion[steps[nextIncompleteStepIndex]?.id]) {
@@ -235,6 +151,78 @@ export default function SetupPage() {
setStepId(nextStepId);
};
const steps: ISetupStep[] = [
{
id: "welcome",
layout: "centered" as "centered",
shortTitle: "Welcome",
title: `Welcome`,
body: <Step0Welcome handleContinue={handleContinue} {...stepProps} />,
actions: <></>,
},
// {
// id: "rowyRun",
// shortTitle: `Rowy Run`,
// title: `Set up Rowy Run`,
// body: <Step1RowyRun {...stepProps} />,
// },
// {
// id: "projectOwner",
// shortTitle: `Project owner`,
// title: `Set up project owner`,
// body: <Step2ProjectOwner {...stepProps} />,
// },
{
id: "oauth",
shortTitle: `Access`,
title: `Allow Firebase access`,
body: <Step1Oauth {...stepProps} />,
},
{
id: "project",
shortTitle: `Project`,
title: `Select project`,
body: <Step2Project {...stepProps} />,
},
{
id: "rules",
shortTitle: `Firestore Rules`,
title: `Set up Firestore Rules`,
body: <Step3Rules {...stepProps} />,
},
{
id: "storageRules",
shortTitle: `Storage Rules`,
title: `Set up Firestore Rules`,
body: <Step3Rules {...stepProps} />,
},
{
id: "finish",
layout: "centered" as "centered",
shortTitle: `Finish`,
title: `Youre all set up!`,
body: <Step5Finish />,
// actions: (
// <Button
// variant="contained"
// color="primary"
// component={Link}
// to={routes.home}
// sx={{ ml: 1 }}
// >
// Continue to Rowy
// </Button>
// ),
},
].filter((x) => x.id);
const step =
steps.find((step) => step.id === (stepId || steps[0].id)) ?? steps[0];
const stepIndex = steps.findIndex(
(step) => step.id === (stepId || steps[0].id)
);
const listedSteps = steps.filter((step) => step.layout !== "centered");
return (
<Wrapper>
<BrandedBackground />
@@ -243,18 +231,17 @@ export default function SetupPage() {
elevation={4}
sx={{
backgroundColor: (theme) =>
alpha(theme.palette.background.paper, 0.5),
alpha(theme.palette.background.paper, 0.75),
backdropFilter: "blur(20px) saturate(150%)",
maxWidth: BASE_WIDTH,
width: (theme) => `calc(100vw - ${theme.spacing(2)})`,
maxHeight: (theme) =>
height: (theme) =>
`calc(${
fullScreenHeight > 0 ? `${fullScreenHeight}px` : "100vh"
} - ${theme.spacing(
2
)} - env(safe-area-inset-top) - env(safe-area-inset-bottom))`,
height: BASE_WIDTH * 0.75,
resize: "both",
p: 0,
@@ -393,31 +380,32 @@ export default function SetupPage() {
</>
)}
<form
onSubmit={(e) => {
e.preventDefault();
try {
handleContinue();
} catch (e: any) {
throw new Error(e.message);
}
return false;
}}
>
<DialogActions>
{step.actions ?? (
<LoadingButton
{step.layout !== "centered" && (
<form
onSubmit={(e) => {
e.preventDefault();
try {
handleContinue();
} catch (e: any) {
throw new Error(e.message);
}
return false;
}}
>
<DialogActions>
<Button
variant="contained"
color="primary"
size="large"
type="submit"
loading={checkingAllSteps}
// loading={checkingAllSteps}
disabled={!completion[stepId]}
>
Continue
</LoadingButton>
)}
</DialogActions>
</form>
</Button>
</DialogActions>
</form>
)}
</Paper>
</Wrapper>
);