Skip to content

Commit

Permalink
implement stepper (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdi-torabiv authored Jul 30, 2024
1 parent 9fe713b commit fbb0345
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 1 deletion.
81 changes: 81 additions & 0 deletions src/components/shared/CustomStepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react';
import { Stepper, Step, StepLabel, StepIconProps, StepConnector, styled, stepConnectorClasses } from '@mui/material';
import Check from '@mui/icons-material/Check';

interface Step {
label: string;
}

interface StepperComponentProps {
steps: Step[];
activeStep: number;
}

const CustomConnector = styled(StepConnector)(({ theme }) => ({
[`&.${stepConnectorClasses.alternativeLabel}`]: {
top: 22,
},
[`&.${stepConnectorClasses.active}`]: {
[`& .${stepConnectorClasses.line}`]: {
backgroundImage: 'linear-gradient( 95deg, #4200FF 0%, #4200FF 50%, #4200FF 100%)',
},
},
[`&.${stepConnectorClasses.completed}`]: {
[`& .${stepConnectorClasses.line}`]: {
backgroundImage: 'linear-gradient( 95deg, #4200FF 0%, #4200FF 50%, #4200FF 100%)',
},
},
[`& .${stepConnectorClasses.line}`]: {
height: 3,
border: 0,
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[800] : '#eaeaf0',
borderRadius: 1,
},
}));

const CustomStepIconRoot = styled('div')<{
ownerState: { completed?: boolean; active?: boolean };
}>(({ theme, ownerState }) => ({
backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[700] : '#ccc',
zIndex: 1,
color: '#fff',
width: 50,
height: 50,
display: 'flex',
borderRadius: '50%',
justifyContent: 'center',
alignItems: 'center',
...(ownerState.active && {
backgroundImage:
'linear-gradient( 136deg, #4200FF 0%, #4200FF 50%, #4200FF 100%)',
boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
}),
...(ownerState.completed && {
backgroundImage:
'linear-gradient( 136deg, #4200FF 0%, #4200FF 50%, #4200FF 100%)',
}),
}));

function CustomStepIcon(props: StepIconProps) {
const { active, completed, className } = props;

return (
<CustomStepIconRoot ownerState={{ completed, active }} className={className}>
{completed ? <Check /> : <div>{props.icon}</div>}
</CustomStepIconRoot>
);
}

const StepperComponent: React.FC<StepperComponentProps> = ({ steps, activeStep }) => {
return (
<Stepper alternativeLabel activeStep={activeStep} connector={<CustomConnector />}>
{steps.map((step, index) => (
<Step key={index}>
<StepLabel StepIconComponent={CustomStepIcon}>{step.label}</StepLabel>
</Step>
))}
</Stepper>
);
};

export default StepperComponent;
26 changes: 26 additions & 0 deletions src/components/shared/StepperComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import StepperComponent from './CustomStepper';

describe('StepperComponent', () => {
const steps = [
{ label: 'Auth' },
{ label: 'Attest' },
{ label: 'Transact' }
];

it('renders all step labels correctly', () => {
render(<StepperComponent steps={steps} activeStep={0} />);

steps.forEach(step => {
expect(screen.getByText(step.label)).toBeInTheDocument();
});
});

it('highlights the active step correctly', () => {
render(<StepperComponent steps={steps} activeStep={1} />);

const activeStep = screen.getByText('Attest').closest('.MuiStep-root');
expect(activeStep).toHaveClass('MuiStep-horizontal');
});
});
6 changes: 5 additions & 1 deletion src/libs/theme.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { createTheme } from '@mui/material/styles';

const theme = createTheme({
palette: {},
palette: {
primary: {
main: '#4200FF'
}
},
typography: {
fontFamily: ['DM Sans', 'sans-serif'].join(','),
},
Expand Down
69 changes: 69 additions & 0 deletions src/pages/Identifiers/Attestation/Attestation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useState } from 'react';
import Paper from '@mui/material/Paper';
import StepperComponent from '../../../components/shared/CustomStepper';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';

const steps = [{ label: 'Auth' }, { label: 'Attest' }, { label: 'Transact' }];

export function Attestation() {
const [activeStep, setActiveStep] = useState(0);

const handleNext = () => {
setActiveStep((prevActiveStep) => Math.min(prevActiveStep + 1, steps.length - 1));
};

return (
<Paper className="p-12" sx={{
height: 'calc(100vh - 100px)'
}} variant="elevation" elevation={0}>
<StepperComponent steps={steps} activeStep={activeStep} />
<div className="relative flex justify-center text-center mt-4 top-[12rem]">
{activeStep === 0 && (
<div className="flex flex-col items-center space-y-3">
<Typography variant="h6" fontWeight="bold" color="initial">
Let’s get started!
</Typography>
<Typography variant="body1" color="GrayText">
Please sign in with Discord.
</Typography>
<Button variant="contained" color="primary" onClick={handleNext} className="mt-2">
Sign in with Discord
</Button>
</div>
)}
{activeStep === 1 && (
<div className="flex flex-col items-center space-y-3">
<Typography variant="h6" fontWeight="bold" color="initial">
Generate an attestation.
</Typography>
<Typography variant="body1" color="GrayText">
An attestation is a proof that links your Discord account to your wallet address.
</Typography>
<Button variant="contained" color="primary" onClick={handleNext} className="mt-2">
Create attestation
</Button>
</div>
)}
{activeStep === 2 && (
<div className="flex flex-col items-center space-y-3">
<Typography variant="h6" fontWeight="bold" color="initial">
Sign Transaction.
</Typography>
<Typography variant="body1" color="GrayText">
Signing the transaction will put your attestation on-chain.
</Typography>
<Button variant="contained" color="primary" onClick={handleNext} className="mt-2">
Sign Transaction
</Button>
<Typography variant="body2" color="GrayText" className="mt-2">
This will cost a small amount of gas.
</Typography>
</div>
)}
</div>
</Paper>
);
}

export default Attestation;
3 changes: 3 additions & 0 deletions src/pages/Identifiers/Attestation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Attestation } from './Attestation';

export default Attestation;
5 changes: 5 additions & 0 deletions src/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createBrowserRouter } from 'react-router-dom';
import Dashboard from '../pages/Dashboard';
import Identifiers from '../pages/Identifiers';
import Permissions from '../pages/Permissions';
import Attestation from '../pages/Identifiers/Attestation';

import DefaultLayout from '../layouts/DefaultLayout';

Expand All @@ -20,6 +21,10 @@ export const router = createBrowserRouter([
path: '/identifiers',
element: <Identifiers />,
},
{
path: '/attestation',
element: <Attestation />,
},
{
path: '/permissions',
element: <Permissions />,
Expand Down

0 comments on commit fbb0345

Please sign in to comment.