Created
July 20, 2025 14:43
-
-
Save ruxiang05/38f2dd6998120e8eac491b3fa1a401ea to your computer and use it in GitHub Desktop.
Gigs Provisioning
This file contains hidden or 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 { useReducer } from "react"; | |
| import "./App.css"; | |
| import { | |
| provisioningFormReducer, | |
| provisioningFormInitialState, | |
| ProvisioningContext, | |
| } from "./state/provisioningForm"; | |
| import UserStep from "./components/UserStep"; | |
| import PlanStep from "./components/PlanStep"; | |
| import ConfirmStep from "./components/ConfirmStep"; | |
| import SuccessStep from "./components/SuccessStep"; | |
| const App = () => { | |
| const [state, dispatch] = useReducer( | |
| provisioningFormReducer, | |
| provisioningFormInitialState | |
| ); | |
| const getStep = () => { | |
| switch (state.step) { | |
| case "user": | |
| return <UserStep />; | |
| case "plan": | |
| return <PlanStep />; | |
| case "confirm": | |
| return <ConfirmStep />; | |
| case "success": | |
| return <SuccessStep />; | |
| default: | |
| return null; | |
| } | |
| }; | |
| return ( | |
| <ProvisioningContext.Provider value={{ state, dispatch }}> | |
| <main>{getStep()}</main> | |
| </ProvisioningContext.Provider> | |
| ); | |
| }; | |
| export default App; |
This file contains hidden or 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 { useProvisioning } from "../state/provisioningForm"; | |
| const ConfirmStep = () => { | |
| const { state, dispatch } = useProvisioning(); | |
| const handleConfirm = () => { | |
| dispatch({ | |
| type: "NEXT_STEP", | |
| }); | |
| }; | |
| const handlePrevious = () => { | |
| dispatch({ | |
| type: "PREVIOUS_STEP", | |
| }); | |
| }; | |
| return ( | |
| <> | |
| <h1>Confirm details</h1> | |
| <p>User: {state.user?.name}</p> | |
| <p>Plan: {state.plan?.name}</p> | |
| <button onClick={handlePrevious}>Previous</button> | |
| <button onClick={handleConfirm}>Confirm</button> | |
| </> | |
| ); | |
| }; | |
| export default ConfirmStep; |
This file contains hidden or 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 type { Plan } from "../state/provisioningForm"; | |
| const mockPlans: Plan[] = [ | |
| { | |
| id: "4fa22f3e-9f11-47b8-b025-cc1671e6b7cb", | |
| name: "Starter EU Plan", | |
| limit: 1024, // 1GB | |
| validity: 15, | |
| price: 9, | |
| }, | |
| { | |
| id: "c1a9df68-2e60-4f5e-b1f5-181fd16b5a7f", | |
| name: "Global Frequent Flyer", | |
| limit: 10240, // 10GB | |
| validity: 60, | |
| price: 45, | |
| }, | |
| { | |
| id: "94e51b2e-3665-4a4e-a7b9-ef86e897586b", | |
| name: "Unlimited 30-Day Plan", | |
| limit: 999999, // Effectively unlimited | |
| validity: 30, | |
| price: 85, | |
| }, | |
| { | |
| id: "ed43e4c0-98aa-4c44-bcb2-712c06b0457d", | |
| name: "Asia-Pacific 5GB", | |
| limit: 5120, | |
| validity: 20, | |
| price: 25, | |
| }, | |
| { | |
| id: "21b4df15-7cf3-43a2-ae87-5fa57dffe228", | |
| name: "Weekend Travel Plan", | |
| limit: 750, // 750MB | |
| validity: 3, | |
| price: 4, | |
| }, | |
| ]; | |
| export default mockPlans; |
This file contains hidden or 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 mockPlans from "../mocks/plans"; | |
| import { useProvisioning } from "../state/provisioningForm"; | |
| const PlanStep = () => { | |
| const { state, dispatch } = useProvisioning(); | |
| const handlePlanChange = (event: React.ChangeEvent<HTMLSelectElement>) => { | |
| const planId = event.target.value; | |
| const selectedPlan = mockPlans.find((p) => p.id === planId); | |
| dispatch({ | |
| type: "SET_PLAN", | |
| value: selectedPlan, | |
| }); | |
| }; | |
| const handlePrevious = () => { | |
| dispatch({ | |
| type: "PREVIOUS_STEP", | |
| }); | |
| }; | |
| const handleNext = () => { | |
| dispatch({ | |
| type: "NEXT_STEP", | |
| }); | |
| }; | |
| return ( | |
| <> | |
| <h1>Select Plan</h1> | |
| <select value={state.plan?.id || ""} onChange={handlePlanChange}> | |
| <option value="" disabled> | |
| Select a plan | |
| </option> | |
| {mockPlans.map((plan) => ( | |
| <option key={plan.id} value={plan.id}> | |
| {plan.name} - ${plan.price} ({plan.limit / 1024} GB, {plan.validity}{" "} | |
| days) | |
| </option> | |
| ))} | |
| </select> | |
| <button onClick={handlePrevious}>Previous</button> | |
| <button onClick={handleNext}>Next</button> | |
| </> | |
| ); | |
| }; | |
| export default PlanStep; |
This file contains hidden or 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 { createContext, useContext } from "react"; | |
| type ProvisioningFormActionType = | |
| | "SET_USER" | |
| | "SET_PLAN" | |
| | "NEXT_STEP" | |
| | "PREVIOUS_STEP"; | |
| type Step = "user" | "plan" | "confirm" | "success"; | |
| export interface User { | |
| id: string; | |
| name: string; | |
| email: string; | |
| } | |
| export interface Plan { | |
| id: string; | |
| name: string; | |
| price: number; | |
| limit: number; | |
| validity: number; | |
| } | |
| interface ProvisioningFormState { | |
| step: Step; | |
| user: User | null; | |
| plan: Plan | null; | |
| } | |
| interface ProvisioningFormAction { | |
| type: ProvisioningFormActionType; | |
| value?: User | Plan | Step; | |
| } | |
| const provisioningFormInitialState: ProvisioningFormState = { | |
| step: "user", | |
| user: null, | |
| plan: null, | |
| }; | |
| const nextStep = (state: ProvisioningFormState): Step => { | |
| switch (state.step) { | |
| case "user": | |
| return "plan"; | |
| case "plan": | |
| return "confirm"; | |
| case "confirm": | |
| return "success"; | |
| default: | |
| return "user"; | |
| } | |
| }; | |
| const previousStep = (state: ProvisioningFormState): Step => { | |
| switch (state.step) { | |
| case "plan": | |
| return "user"; | |
| case "confirm": | |
| return "plan"; | |
| case "success": | |
| return "confirm"; | |
| default: | |
| return "user"; | |
| } | |
| }; | |
| const provisioningFormReducer = ( | |
| state: ProvisioningFormState, | |
| action: ProvisioningFormAction | |
| ) => { | |
| switch (action.type) { | |
| case "SET_USER": | |
| return { | |
| ...state, | |
| user: action.value as User, | |
| }; | |
| case "SET_PLAN": | |
| return { | |
| ...state, | |
| plan: action.value as Plan, | |
| }; | |
| case "NEXT_STEP": | |
| return { | |
| ...state, | |
| step: nextStep(state), | |
| }; | |
| case "PREVIOUS_STEP": | |
| return { | |
| ...state, | |
| step: previousStep(state), | |
| }; | |
| default: | |
| return state; | |
| } | |
| }; | |
| const ProvisioningContext = createContext<{ | |
| state: ProvisioningFormState; | |
| dispatch: React.Dispatch<ProvisioningFormAction>; | |
| } | null>(null); | |
| const useProvisioning = () => { | |
| const context = useContext(ProvisioningContext); | |
| if (!context) { | |
| throw new Error( | |
| "useProvisioning must be used within a ProvisioningContext.Provider" | |
| ); | |
| } | |
| return context; | |
| }; | |
| export { | |
| provisioningFormInitialState, | |
| provisioningFormReducer, | |
| ProvisioningContext, | |
| useProvisioning, | |
| }; |
This file contains hidden or 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
| const SuccessStep = () => { | |
| return <h1>Provisioning Successful!</h1>; | |
| }; | |
| export default SuccessStep; |
This file contains hidden or 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 type { User } from "../state/provisioningForm"; | |
| const mockUsers: User[] = [ | |
| { | |
| id: "a3e1c8a1-e0ff-4f32-b47f-1eb786f1abc3", | |
| name: "Dr. Ada Lovelace", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "b9c3dff5-3e13-4e06-8c6f-5e2aa6a2d9f1", | |
| name: "Alan Turing", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "f483da9d-c2c5-42b1-98b4-03d0f9f93755", | |
| name: "Grace Hopper", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "91dfc0b6-342c-4f38-bb2b-fc25eb38d79a", | |
| name: "Katherine Johnson", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "d7c52803-3a49-419b-a8d1-a3deedbeb79b", | |
| name: "Margaret Hamilton", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "b16d93ec-3a5a-43c8-ae68-ba8e57c06113", | |
| name: "Tim Berners-Lee", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "0dffe378-3b58-479e-8e30-fe24da539f7e", | |
| name: "Linus Torvalds", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "bfe00135-f5f5-4696-b4c4-c817912b420c", | |
| name: "Barbara Liskov", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "17bbf826-5d3f-4a1c-a1d9-293d8b09e92f", | |
| name: "Edsger Dijkstra", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "fb0f3343-81bc-4d59-b787-5b5b8e521bbc", | |
| name: "Radia Perlman", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "f6e5dfaf-a729-4a5a-b63a-55f78719c86e", | |
| name: "Donald Knuth", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "3b65e37d-9e5f-414e-b8e2-325d9c504aad", | |
| name: "Frances Allen", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "153f0ea3-cf28-4195-9c07-2434e36e0bd3", | |
| name: "Jean Bartik", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "875a7d5d-3604-400a-9bd8-65013a1c68d4", | |
| name: "Dennis Ritchie", | |
| email: "[email protected]", | |
| }, | |
| { | |
| id: "feade69e-1a62-4a32-b497-2d4fef606f2c", | |
| name: "Stephanie Shirley", | |
| email: "[email protected]", | |
| }, | |
| ]; | |
| export default mockUsers; |
This file contains hidden or 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 { useProvisioning } from "../state/provisioningForm"; | |
| import mockUsers from "../mocks/users"; | |
| const UserStep = () => { | |
| const { state, dispatch } = useProvisioning(); | |
| const handleUserChange = (event: React.ChangeEvent<HTMLSelectElement>) => { | |
| const userId = event.target.value; | |
| const selectedUser = mockUsers.find((u) => u.id === userId); | |
| dispatch({ | |
| type: "SET_USER", | |
| value: selectedUser, | |
| }); | |
| }; | |
| const handleNext = () => { | |
| dispatch({ | |
| type: "NEXT_STEP", | |
| }); | |
| }; | |
| return ( | |
| <> | |
| <h1>Select User</h1> | |
| <select value={state.user?.id || ""} onChange={handleUserChange}> | |
| <option value="" disabled> | |
| Select a user | |
| </option> | |
| {mockUsers.map((user) => ( | |
| <option key={user.id} value={user.id}> | |
| {user.name} | |
| </option> | |
| ))} | |
| </select> | |
| <button onClick={handleNext}>Next</button> | |
| </> | |
| ); | |
| }; | |
| export default UserStep; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment