Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: anthony guido technical assessment #2

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
770 changes: 737 additions & 33 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/icons-material": "^6.1.6",
"@mui/material": "^6.1.6",
"@reduxjs/toolkit": "^2.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"redux": "^5.0.1"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
Expand Down
42 changes: 0 additions & 42 deletions src/App.css

This file was deleted.

7 changes: 7 additions & 0 deletions src/App.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Box, styled } from "@mui/material";

export const AppWrapper = styled(Box)(({ theme }) => ({
maxWidth: theme.breakpoints.values.sm,
margin: "auto",
padding: theme.spacing(5),
}));
41 changes: 11 additions & 30 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,16 @@
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import { Provider } from "react-redux";
import { AppWrapper } from "./App.styles";
import store from "./redux/store";
import { Home } from "./pages";

function App() {
const [count, setCount] = useState(0)

return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
<Provider store={store}>
<AppWrapper>
<Home />
</AppWrapper>
</Provider>
);
}

export default App
export default App;
7 changes: 7 additions & 0 deletions src/components/Wizard/Wizard.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Box, styled } from "@mui/material";

export const ContentWrapper = styled(Box)(({ theme }) => ({
minHeight: "300px",
margin: "auto",
paddingTop: theme.spacing(7),
}));
34 changes: 34 additions & 0 deletions src/components/Wizard/Wizard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from "react";
import { WizardProps } from "./Wizard.types";
import { WizardHeader } from "./components";
import { WizardButtons } from "./components/WizardButtons";
import { ContentWrapper } from "./Wizard.styles";

export const Wizard: React.FC<WizardProps> = ({ steps, onSubmit }) => {
const [step, setStep] = useState(0);
const {
content,
canProceedFurther,
canProceedBack = true,
isLoading,
} = steps[step];
const headerSteps: string[] = steps.map(({ label }) => {
return label;
});

return (
<section>
<WizardHeader steps={headerSteps} currentStep={step} />
<ContentWrapper>{content}</ContentWrapper>
<WizardButtons
setStep={setStep}
currentStep={step}
isFirstStep={step === 0}
isLastStep={step === steps.length - 1}
canProceedFurther={canProceedFurther && !isLoading}
canProceedBack={canProceedBack}
onSubmit={onSubmit}
/>
</section>
);
};
12 changes: 12 additions & 0 deletions src/components/Wizard/Wizard.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type Step = {
label: string;
content: React.ReactNode;
canProceedFurther: boolean;
canProceedBack?: boolean;
isLoading?: boolean;
};

export type WizardProps = {
onSubmit: () => Promise<void>;
steps: Step[];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Box, styled } from "@mui/material";

export const ButtonWrapper = styled(Box)(({ theme }) => ({
display: "flex",
justifyContent: "space-between",
paddingTop: theme.spacing(2),
}));
43 changes: 43 additions & 0 deletions src/components/Wizard/components/WizardButtons/WizardButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Button } from "@mui/material";
import { WizardButtonsProps } from "./WizardButtons.types";
import { ButtonWrapper } from "./WizardButtons.styles";

export const WizardButtons: React.FC<WizardButtonsProps> = ({
currentStep,
setStep,
isFirstStep,
isLastStep,
canProceedFurther,
canProceedBack,
onSubmit,
}) => {
const onPreviousStepChange = () => {
setStep(currentStep - 1);
};

const onNextStepChange = () => {
if (isLastStep) {
onSubmit();
} else {
setStep(currentStep + 1);
}
};

return (
<ButtonWrapper>
<Button
disabled={isFirstStep || !canProceedBack}
onClick={onPreviousStepChange}
>
Previous
</Button>
<Button
onClick={onNextStepChange}
disabled={!canProceedFurther}
variant="contained"
>
{isLastStep ? "Submit" : "Next"}
</Button>
</ButtonWrapper>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { WizardProps } from "../../Wizard.types";

export type WizardButtonsProps = {
setStep: (step: number) => void;
currentStep: number;
isFirstStep: boolean;
isLastStep: boolean;
canProceedFurther: boolean;
canProceedBack: boolean;
} & Pick<WizardProps, "onSubmit">;
1 change: 1 addition & 0 deletions src/components/Wizard/components/WizardButtons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./WizardButtons";
17 changes: 17 additions & 0 deletions src/components/Wizard/components/WizardHeader/WizardHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Stepper, Step, StepLabel } from "@mui/material";
import { WizardHeaderProps } from "./WizardHeader.types";

export const WizardHeader: React.FC<WizardHeaderProps> = ({
currentStep,
steps,
}) => {
return (
<Stepper activeStep={currentStep} alternativeLabel>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type WizardHeaderProps = {
steps: string[];
currentStep: number;
};
1 change: 1 addition & 0 deletions src/components/Wizard/components/WizardHeader/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./WizardHeader";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Feature } from "./FeatureSelectList.types";

export const FEATURE_OPTIONS: Feature[] = [
{ id: "1", name: "Feature A", description: "Description for Feature A" },
{ id: "2", name: "Feature B", description: "Description for Feature B" },
{ id: "3", name: "Feature C", description: "Description for Feature C" },
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
Checkbox,
List,
ListItem,
ListItemIcon,
ListItemText,
} from "@mui/material";
import { SelectFormProps } from "./FeatureSelectList.types";
import { useSelectedFeatures } from "../../../../../hooks/useSelectedFeatures";

export const FeatureSelectList: React.FC<SelectFormProps> = ({ options }) => {
const { selectedFeatureIds, updateSelectedFeatures } = useSelectedFeatures();

const handleToggle = (featureId: string) => {
if (selectedFeatureIds.includes(featureId)) {
updateSelectedFeatures(
selectedFeatureIds.filter((id) => id !== featureId)
);
} else {
updateSelectedFeatures([...selectedFeatureIds, featureId]);
}
};

return (
<List>
{options.map(({ id, name, description }) => (
<ListItem key={id} onClick={() => handleToggle(id)}>
<ListItemIcon>
<Checkbox checked={selectedFeatureIds.includes(id)} />
</ListItemIcon>
<ListItemText primary={name} secondary={description} />
</ListItem>
))}
</List>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type Feature = {
id: string;
name: string;
description: string;
};

export type SelectFormProps = {
options: Feature[];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./FeatureSelectList";
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { styled, Typography } from "@mui/material";

export const CenteredTypography = styled(Typography)(() => ({
textAlign: 'center'
}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Alert, Box, Grid, Typography } from "@mui/material";
import { FEATURE_OPTIONS } from "../FeatureSelectList/FeatureSelectList.constant";
import { Feature } from "../FeatureSelectList/FeatureSelectList.types";
import {
useUserInfo,
useSelectedFeatures,
useInfoSubmitted,
} from "../../../../../hooks";

export const ReviewScreen = () => {
const { userName, userDescription } = useUserInfo();
const { selectedFeatureIds } = useSelectedFeatures();
const { isSuccess } = useInfoSubmitted();

const selectedFeatures: Feature[] = FEATURE_OPTIONS.filter((feature) =>
selectedFeatureIds.includes(feature.id)
);

return (
<>
{isSuccess && (
<Alert severity="success">
Your account has been successfully created!
</Alert>
)}
<Grid container spacing={2} flexDirection="column">
<Grid item>
<Typography variant="h6">Name</Typography>
<Typography>{userName}</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Description</Typography>
<Typography>{userDescription}</Typography>
</Grid>
<Grid item>
<Typography variant="h6">Selected features</Typography>
{selectedFeatures.map(({ id, name, description }) => (
<Box key={id}>
<Typography>{name}</Typography>
<Typography variant="caption">{description}</Typography>
</Box>
))}
</Grid>
</Grid>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./ReviewScreen";
Loading
Loading