Skip to content

Commit

Permalink
Merge pull request #12 from bitovi/feature/exercise-routing
Browse files Browse the repository at this point in the history
Feature/exercise routing
  • Loading branch information
DavidNic11 authored Jul 23, 2024
2 parents 936cb4f + 7c18130 commit 890015e
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 10 deletions.
2 changes: 1 addition & 1 deletion packages/shell/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default defineConfig({
catalog: `catalog@${process.env.MFE_URL_CATALOG}/remoteEntry.js`,
order: `order@${process.env.MFE_URL_ORDER}/remoteEntry.js`,
profile: `profile@${process.env.MFE_URL_PROFILE}/remoteEntry.js`,
marketing: `marketing@https://marketing-mfe.bitovi-sandbox.com/remoteEntry.js`,
marketing: `marketing@${process.env.MFE_URL_MARKETING}/remoteEntry.js`,
workshop: `workshop@${process.env.MFE_URL_WORKSHOP}/workshop.js`,
},
shared: {
Expand Down
12 changes: 6 additions & 6 deletions packages/shell/src/scenes/Login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ const LoginScene: LoginScene = () => {

const navigate = useNavigate();

const handleLoginSuccess = () => {
setIsLoggedIn(true);
navigate("/shop");
};

return (
<ErrorBoundary fallback={<LoginError />}>
<Suspense fallback={<LoginSkeleton />}>
<Login
onLoginSuccess={() => {
setIsLoggedIn(true);
navigate("/shop");
}}
/>
<Login onLoginSuccess={handleLoginSuccess} />
</Suspense>
</ErrorBoundary>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/workshop/src/scenes/Exercises/Exercises.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import FaultTolerance from "./components/FaultTolerance";
import AddingMoreMicroFrontends from "./components/AddingMoreMicroFrontends";

import type { WorkshopScene } from "shared/workshop";
import SettingUpRoutes from "./components/SettingUpRoutes";
import CheckoutFlow from "./components/CheckoutFlow";

const Workshop: WorkshopScene = () => {
return (
Expand All @@ -19,6 +21,8 @@ const Workshop: WorkshopScene = () => {
<Route path="exercise-2" element={<SharingCommonModules />} />
<Route path="exercise-3" element={<FaultTolerance />} />
<Route path="exercise-4" element={<AddingMoreMicroFrontends />} />
<Route path="exercise-5" element={<SettingUpRoutes />} />
<Route path="exercise-6" element={<CheckoutFlow />} />
</Route>
</Routes>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Anchor, Code, Grid, Image, List, Text, Title } from "@mantine/core";

import ExerciseLayout from "../../shared/components/ExerciseLayout";

import shipping from "./assets/shipping.png";
import payment from "./assets/payment.png";

const readLogin = `import { readLocalStorageValue } from "@mantine/hooks";
// ...
const isLoggedIn = readLocalStorageValue<boolean>({ key: "logged-in" });`;

const setLogin = `const [, setIsLoggedIn] = useLocalStorage({
key: "logged-in",
defaultValue: false,
});
const handleLoginSuccess = () => {
setIsLoggedIn(true);
};
}`;

const CheckoutFlow = () => {
return (
<ExerciseLayout
title="Checkout Flow"
previous="../exercise-5"
next="../exercise-7"
>
<Text>
We have a catalog but no way to purchase any of our items, so it's high
time we addressed that. The application needs two parts.
</Text>
<List py="lg">
<List.Item>User authentication</List.Item>
<List.Item>The checkout flow</List.Item>
</List>
<Title py="xl" order={2}>
User Authentication
</Title>
<Text>
Users should only be able to view the shop when authenticated. To
achieve this, we must implement an authentication check before allowing
access to the shop. Users who are not authenticated should be redirected
to the login page. You can use the following code to check if a user is
authenticated
</Text>
<Code my="lg" block>
{readLogin}
</Code>
<Text>
The login micro-frontend (MFE) should be loaded at the{" "}
<Code>/login</Code> route, ensuring it handles user authentication and
redirects authenticated users back to the shop.
</Text>
<Text pt="md">
The login MFE (<Code>profile/login</Code>) accepts an{" "}
<Code>onLoginSuccess</Code> prop. In the component that loads the login
MFE, you can add the following code to handle the authentication portion
of the requirements. However, you will need to add the redirection
logic; here's a{" "}
<Anchor href="https://reactrouter.com/en/main/hooks/use-navigate">
hint.
</Anchor>
</Text>
<Code my="lg" block>
{setLogin}
</Code>
<Title py="xl" order={2}>
The Checkout Flow
</Title>
<Text>
We need to implement a checkout flow to enable users to purchase items
from the catalog. This will involve consuming and updating the checkout
MFE (<Code>profile/checkout</Code>). The checkout flow can be described
as follows.
</Text>
<List py="lg" type="ordered">
<List.Item>
The user visits/navigates to <Code>/order</Code>, where they are shown
their order summary and a form to input their shipping information.
</List.Item>
<List.Item>
After entering their shipping information and pressing “continue”, the
user is moved on to <Code>order/checkout</Code> where they are still
able to view their order summary but the form is now a payment form.
</List.Item>
</List>
<Grid my="md">
<Grid.Col span={{ sm: 12, md: 6 }}>
<Image src={shipping} />
</Grid.Col>
<Grid.Col span={{ sm: 12, md: 6 }}>
<Image src={payment} />
</Grid.Col>
</Grid>
<Text>
Inside the checkout scene, a lot of the infrastructure is already in
place. To achieve this flow, you'll need to:
</Text>
<List py="lg" type="ordered">
<List.Item>
Update the shell application to load and defer the <Code>/order</Code>{" "}
route to the
<Code>order/checkout</Code> MFE.
</List.Item>
<List.Item>
Update the <Code>Checkout</Code> component in{" "}
<Code>src/scenes/Checkout/Checkout.tsx</Code> file to handle the
layout and subroutes.
</List.Item>
<List.Item>
Update the <Code>Layout</Code> component in
<Code>src/scenes/Checkout/components/Layout/Layout.tsx</Code> to
render the proper view for the app.
</List.Item>
</List>
</ExerciseLayout>
);
};

export default CheckoutFlow;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CheckoutFlow";
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,24 @@ export const exercises: ExerciseData[] = [
to: "exercise-4",
},
{
title: "Individual and Shared Routes",
title: "Setting Up Routes",
subTitle: "Most apps (ours included) need routing",
to: "exercise-5",
},
{
title: "Checkout Flow",
subTitle: "Our users will need a way to purchase items",
to: "exercise-6",
},
{
title: "Pub-Sub and Micro-Frontends",
subTitle: "Add MFE to MFE communication with pub-sub",
to: "exercise-6",
to: "exercise-7",
},
{
title: "The URL for Communication",
subTitle: "The URL can also be used to communicate data across MFEs",
to: "exercise-7",
to: "exercise-8",
},
{
title: "Completed",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Code, List, Text, Title } from "@mantine/core";
import ExerciseLayout from "../../shared/components/ExerciseLayout";

const SettingUpRoutes = () => {
return (
<ExerciseLayout
title="Setting Up Routes"
next="../exercise-6"
previous="../exercise-3"
>
<Text>
We have several pages left to set up for our application. Let's take a
moment to wire up the following MFEs with their respective routes. Each
MFE should maintain the site's layout.
</Text>
<List py="lg">
<List.Item>
<Code>marketing/about</Code> at <Code>/about</Code>
</List.Item>
<List.Item>
<Code>marketing/contact</Code> at <Code>/contact</Code>
</List.Item>
<List.Item>
<Code>profile/account</Code> at <Code>/account</Code>
</List.Item>
</List>
<Text>
Once added, you should be able to navigate to each page using the
header. The account page can be reached by clicking on the user icon.
</Text>

<Title order={2} py="xl">
Viewing Catalog Items
</Title>
<Text pt="md">
Currently, there is no way to view the details of the items in the
catalog list. Let's fix that. Create a dynamic segment under the{" "}
<Code>/shop</Code>
route so that <Code>shop/item/1</Code> and <Code>shop/item/2</Code>{" "}
render the catalog/item MFE.
</Text>
<Text pt="md">
After setting up the routes, update the <Code>CatalogItem</Code>{" "}
component in
<Code>catalog/src/scene/CatalogItem</Code> to use the dynamic path
segment instead of the currently hard-coded id variable.
</Text>
</ExerciseLayout>
);
};

export default SettingUpRoutes;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./SettingUpRoutes";

0 comments on commit 890015e

Please sign in to comment.