Skip to content

Commit

Permalink
Merge pull request #3 from oslabs-beta/joy/newfrontend
Browse files Browse the repository at this point in the history
`feat: `add a Next button and hover effects on Steppers on the Quick Start Page
  • Loading branch information
misterjoecool authored May 21, 2024
2 parents bdd759a + 2c9551d commit 8d984a4
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 234 deletions.
219 changes: 103 additions & 116 deletions frontend/components/views/QuickStartView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import React, { useState } from 'react';
import styled from 'styled-components';
import logo from '../../../assets/logo/seeqr_dock.png';
import '../../lib/style.css';
import { greyPrimary } from '../../style-variables';

interface QuickStartViewProps {
show: boolean;
}

// welcome page container w/o sidebar
const PageContainer = styled.a`
display: flex;
flex-direction: column;
Expand All @@ -23,61 +24,73 @@ const PageContainer = styled.a`
height: auto;
width: auto;
`;

// each stepper component
const StyledStepper = styled(Stepper)`
margin: 60px 0px 20px 0px;
background: transparent;
margin: 60px 10px 20px 0px;
`;

// stepButton with all elements inside
const StyledStepButton = styled(StepButton)`
padding-top: 25px;
& :hover {
background-color: ${greyPrimary};
transition: 200ms ease-in-out;
}
`;
// Text label for each stepper
const StyledStepLabel = styled(StepLabel)`
width: 10vw;
& .MuiStepLabel-label {
font-size: clamp(1rem, 1.28vw, 1.3rem);
}
`;

// text instructions div
const StyledTypographyInstructions = styled.div`
font-size: clamp(1rem, 2.2vw, 1.2rem);
text-align: center;
width: 40vw;
width: 50vw;
`;

// title: "welcome to SeeQR"
const StyledTypographyTitle = styled(Typography)`
font-size: clamp(2rem, 35vw, 3rem);
`;

// container div for btn back & btn complete
const NavButtons = styled.div`
margin: 15px auto;
width: 80%;
display: flex;
flex-direction: row;
justify-content: space-around;
margin-bottom: 15px;
`;

// container for the text instructions and navBtn
const StepContent = styled.div`
min-height: 30vw;
display: flex;
flex-direction: column;
justify-content: center;
justify-content: space-between;
align-items: center;
margin-top: 20px;
`;

// step list ul
const StepList = styled.ul`
text-align: left;
font-size: 0.9em;
list-style: circle;
& li {
margin-top: 7px;
}
`;

function getSteps() {
return [
'Set Up Servers and Permissions',
'Import/ Export a Database',
'Create New Queries',
'Saving/Loading Queries',
'Compare Queries',
];
}

function getStepContent(step: number) {
// array to hold all the steps
const steps: string[] = [
'Set Up Servers and Permissions',
'Import/ Export a Database',
'Create New Queries',
'Saving/Loading Queries',
'Compare Queries',
];
// func to help get step instructions and render it
function getStepContent(step: number): JSX.Element | string {
switch (step) {
case 0:
return (
Expand All @@ -90,15 +103,16 @@ function getStepContent(step: number) {
<li> Run server(s) in the background</li>
<li>Ensure that PATH is enabled</li>
<li>
MySQL username defaults to 'root' and postgres username defaults to 'postgres'

MySQL username defaults to &quot;root&quot; and postgres username
defaults to &quot;postgres&quot;
</li>
<li>
MySQL and postgres password will be your password to log into mySQL and postgres database
MySQL and postgres password will be your password to log into
mySQL and postgres database
</li>
<li>
Ports for PostgresSQL and MySQL are defaulted to 5432’ and
3306, respectively
Ports for PostgresSQL and MySQL are defaulted to &quot;5432&quot;
and &quot;3306&quot;, respectively
</li>
<li>Enable full permissions for database manipulation</li>
</StepList>
Expand Down Expand Up @@ -150,7 +164,8 @@ function getStepContent(step: number) {
query
</li>
<li>
Use the previous queries dropdown to view and select previously inputted queries
Use the previous queries dropdown to view and select previously
inputted queries
</li>
<li>Select &quot;RUN QUERY&quot; button to execute</li>
<li>
Expand Down Expand Up @@ -209,151 +224,123 @@ function getStepContent(step: number) {
function QuickStartView({ show }: QuickStartViewProps) {
if (!show) return null;
const [activeStep, setActiveStep] = useState(0);
const [completed, setCompleted] = useState(new Set<number>());
const [skipped, setSkipped] = useState(new Set<number>());
const steps = getSteps();

const totalSteps = () => getSteps().length;

const isStepOptional = (step: number) => step === null;
const [completed, setCompleted] = useState<{ [k: number]: boolean }>({});

const handleSkip = () => {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this
// it should never occur unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
const totalSteps = () => steps.length;

setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped((prevSkipped) => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};

const skippedSteps = () => skipped.size;
// count completed steps number
const completedSteps = (): number => Object.keys(completed).length;

const completedSteps = () => completed.size;
// check if it is the last step
const isLastStep = (): boolean => activeStep === totalSteps() - 1;

const allStepsCompleted = () =>
completedSteps() === totalSteps() - skippedSteps();

const isLastStep = () => activeStep === totalSteps() - 1;
// check if all steps are completed
const allStepsCompleted = (): boolean => completedSteps() === totalSteps();

// func to handle next btn
const handleNext = () => {
const newActiveStep =
isLastStep() && !allStepsCompleted()
? // It's the last step, but not all steps have been completed
// find the first step that has been completed
steps.findIndex((step, i) => !completed.has(i))
steps.findIndex((step, i) => !(i in completed))
: activeStep + 1;

setActiveStep(newActiveStep);
};

// func to handle back btn
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};

// func to set activeStep
const handleStep = (step: number) => () => {
setActiveStep(step);
};

// func to handle each complete step btn
const handleComplete = () => {
const newCompleted = new Set(completed);
newCompleted.add(activeStep);
const newCompleted = completed;
newCompleted[activeStep] = true;
setCompleted(newCompleted);

if (completed.size !== totalSteps() - skippedSteps()) {
handleNext();
}
handleNext();
};

// handle reset btn after all steps completed
const handleReset = () => {
setActiveStep(0);
setCompleted(new Set<number>());
setSkipped(new Set<number>());
setCompleted({});
};

const isStepSkipped = (step: number) => skipped.has(step);

function isStepComplete(step: number) {
return completed.has(step);
}

// render components
return (
<PageContainer>
<StyledTypographyTitle align="center">
Welcome to SeeQR
</StyledTypographyTitle>
<img className="step-img" src={logo} alt="Logo" />
<StyledStepper alternativeLabel nonLinear activeStep={activeStep}>
{steps.map((label, index) => {
const stepProps: { completed?: boolean } = {};
const buttonProps: { optional?: React.ReactNode } = {};
if (isStepOptional(index)) {
buttonProps.optional = (
<Typography variant="caption">Optional</Typography>
);
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} {...stepProps} completed={isStepComplete(index)}>
<StepButton onClick={handleStep(index)} {...buttonProps}>
<StyledStepLabel className="stepper">{label}</StyledStepLabel>
</StepButton>
</Step>
);
})}
{steps.map((label, index) => (
<Step key={label} completed={completed[index]}>
<StyledStepButton onClick={handleStep(index)}>
<StyledStepLabel className="stepper">{label}</StyledStepLabel>
</StyledStepButton>
</Step>
))}
</StyledStepper>
<div>
{allStepsCompleted() ? (
<div>
<div className="step-completed-div">
<StyledTypographyInstructions className="step-instructions">
All steps completed - you&apos;re ready to use SeeQr!
</StyledTypographyInstructions>
<Button onClick={handleReset}>Reset</Button>
<Button
variant="outlined"
color="primary"
onClick={handleReset}
className="step-btn"
id="step-reset-btn"
>
RESET
</Button>
</div>
) : (
<StepContent>
{getStepContent(activeStep)}
<NavButtons>
<Button
variant="outlined"
color="primary"
disabled={activeStep === 0}
onClick={handleBack}
className="step-btn"
id="step-back-btn"
>
Back
{activeStep === 0 ? '' : 'BACK'}
</Button>
{isStepOptional(activeStep) && !completed.has(activeStep) && (
<Button
variant="contained"
color="primary"
onClick={handleSkip}
className="step-btn"
>
Skip
</Button>
)}

{activeStep !== steps.length &&
(completed.has(activeStep) ? (
<Typography variant="caption" className="step-completed">
Step
{` ${activeStep + 1} `}
already completed
</Typography>
(completed[activeStep] ? (
<Button
variant="contained"
color="primary"
onClick={handleNext}
className="step-btn"
id="step-next-btn"
>
NEXT
</Button>
) : (
// <Typography variant="caption" className="step-completed-btn">
// {`Step ${activeStep + 1} already`}
// <br /> completed
// </Typography>
<Button
variant="contained"
color="primary"
className="step-btn"
id="step-complete-next-btn"
onClick={handleComplete}
>
{completedSteps() === totalSteps() - 1
? 'Finish'
: 'Complete Step'}
{completedSteps() === totalSteps() - 1 ? 'FINISH' : 'NEXT'}
</Button>
))}
</NavButtons>
Expand Down
Loading

0 comments on commit 8d984a4

Please sign in to comment.