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

🥾 Check Gitcoin score and adjust stepper #24

Merged
merged 10 commits into from
Apr 23, 2024
8 changes: 4 additions & 4 deletions packages/frontend/src/components/form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ export const FormRow = styled.div`
justify-content: space-between;
align-items: center;
width: 100%;
color: ${Colors.White};
color: ${Colors.Black};
`

export const FormHeading = styled.h2`
color: ${Colors.White};
color: ${Colors.Black};
`

export const FormSubHeading = styled.h3`
color: ${Colors.White};
color: ${Colors.Black};
`

export const FormWrapper = styled.div`
Expand All @@ -49,5 +49,5 @@ export const FormWideWrapper = styled(FormSectionWrapper)`

export const FormText = styled.p`
max-width: 440px;
color: ${Colors.White};
color: ${Colors.Black};
`
21 changes: 21 additions & 0 deletions packages/frontend/src/components/icons/ClockIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IconProps } from '@/components/icons/IconBase'

export const ClockIcon = ({ color, size, className }: IconProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 38 38"
fill="none"
color={color}
className={className}
>
<circle cx="19" cy="19" r="19" fill="#0F0F0F" />
<path
d="M33.1714 26.4277C31.8495 28.9498 29.8785 31.0734 27.4618 32.5793C25.0451 34.0853 22.2702 34.919 19.4237 34.9944C16.5772 35.0698 13.7621 34.3842 11.269 33.0083C8.77596 31.6324 6.69525 29.6161 5.24167 27.1675C3.78809 24.7189 3.01431 21.9268 3.0002 19.0793C2.98608 16.2318 3.73215 13.4321 5.16138 10.9693C6.59061 8.50641 8.65123 6.46959 11.1305 5.06905C13.6098 3.66852 16.418 2.95501 19.2651 3.0022L19 19L33.1714 26.4277Z"
fill="white"
/>
</svg>
)
}
1 change: 1 addition & 0 deletions packages/frontend/src/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from './Logo'
export * from './RedirectIcon'
export * from './SearchIcon'
export * from './TruefiLogoIcon'
export * from './ClockIcon'
186 changes: 186 additions & 0 deletions packages/frontend/src/components/stepper/Stepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { Colors } from '@/styles/colors'
import styled from 'styled-components'
import { CrossIcon } from '../icons'

interface StepContent {
name: string
description?: string
}

type StepDescription = 'default' | 'failed'

type Step = Record<StepDescription, StepContent>

type Steps = Step[]

type StepType = 'neutral' | 'success' | 'failure'

interface StepperProps {
steps: Steps
currentStep: number
isFailed: boolean
}

export const Stepper = ({ currentStep, isFailed, steps }: StepperProps) => (
<StepperList>
{steps.map((item, index) => {
const isCurrent = index === currentStep
const status = isCurrent ? 'current' : index < currentStep ? 'completed' : 'next'
const { step, type } = pickStepVersion(item, isFailed && isCurrent, isCurrent)
return <StepperListItem key={index} step={step} status={status} type={type} />
})}
</StepperList>
)

function pickStepVersion(item: Step, IsFailed: boolean, isCurrent: boolean) {
const [step, type]: [StepContent, StepType] =
item.failed && IsFailed ? [item.failed, 'failure'] : [item.default, isCurrent ? 'neutral' : 'success']
return { step, type }
}

type StepStatus = 'current' | 'completed' | 'next'

interface ListItemProps {
step: StepContent
status: StepStatus
type: StepType
}

const StepperListItem = ({ step, status, type }: ListItemProps) => (
<StepperListItemContainer type={type} status={status}>
<StepperBullet type={type} status={status}>
{type === 'failure' && <CrossIcon size={16} color={Colors.RedDark} />}
</StepperBullet>
<StepperItemName next={status === 'next'}>{step.name}</StepperItemName>
<StepperItemDescription current={status === 'current'}>{step.description}</StepperItemDescription>
</StepperListItemContainer>
)

const StepperList = styled.ul`
display: flex;
flex-direction: column;
padding: 0;
margin: 0;
`

function getItemColor(props: DisplayTypeProps) {
switch (props.status) {
case 'current':
return typeToItemColor[props.type]
default:
return Colors.Black
}
}

const typeToItemColor: Record<StepType, string> = {
neutral: Colors.Black,
success: Colors.Black,
failure: Colors.RedDark,
}

const StepperListItemContainer = styled.li<DisplayTypeProps>`
display: grid;
position: relative;
grid-template-areas:
'icon header'
'icon description';
grid-template-columns: 18px auto;
grid-column-gap: 12px;
grid-row-gap: 4px;
margin-top: 36px;
color: ${getItemColor};
transition: all 0.25s ease;

&:before {
content: '';
position: absolute;
left: 9px;
top: 17px;
width: 0px;
border-left: 2px ${({ status }) => (status === 'completed' ? 'solid' : 'dashed')} ${Colors.Black};
height: calc(100% + 19px);
transform: translateX(-50%);
pointer-events: none;
}

&:first-child {
margin-top: 0px;
}

&:last-child {
&:before {
content: unset;
}
}
`
interface DisplayTypeProps {
type: StepType
status: StepStatus
}

const StepperBullet = styled.div<DisplayTypeProps>`
grid-area: icon;
display: flex;
align-items: center;
width: 17px;
height: 17px;
border: 2px solid currentColor;
border-radius: 50%;
background-color: ${({ type, status }) => {
switch (status) {
case 'current':
return typeToBulletBackground[type]
case 'completed':
return Colors.Black
default:
return Colors.White
}
}};

color: ${({ type, status }) => {
switch (status) {
case 'current':
return typeToBulletColor[type]
case 'completed':
return Colors.Black
default:
return Colors.Black
}
}};
`

const typeToBulletBackground: Record<StepType, string> = {
neutral: Colors.White,
failure: Colors.White,
success: Colors.Black,
}

const typeToBulletColor: Record<StepType, string> = {
neutral: Colors.Black,
failure: Colors.RedDark,
success: Colors.Black,
}

interface ItemNameProps {
next?: boolean
}

const StepperItemName = styled.span<ItemNameProps>`
grid-area: header;
font-size: 16px;
line-height: 1;
font-weight: 600;
color: inherit;
opacity: ${(props) => (props.next ? 0.7 : 1)};
`

interface ItemDescriptionProps {
current?: boolean
}

const StepperItemDescription = styled.span<ItemDescriptionProps>`
grid-area: description;
color: ${Colors.Black};
opacity: ${(props) => (props.current ? 1 : 0.7)};
transition: all 0.25s ease;
`
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const Wrapper = styled.div`
margin-left: -170px;
width: 724px;
height: 450px;
background-color: ${Colors.Blue};
background-color: ${Colors.Pink};
position: relative;
z-index: 1;
`
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { SeparatorWithText } from '@/components/common/Separator'

export const CheckGitcoinPassword = () => {
return (
<ConnectFormWrapper>
<Wrapper>
<FormHeading>Check GitCoin Passport</FormHeading>
<FormRow>
<span>To place a bid we need to check your score. By verifying your score we checking if you are a human.</span>
Expand All @@ -18,11 +18,11 @@ export const CheckGitcoinPassword = () => {
</span>
</FormRow>
<Button wide>Create a Gitcoin Passport</Button>
</ConnectFormWrapper>
</Wrapper>
)
}

const ConnectFormWrapper = styled(FormWrapper)`
const Wrapper = styled(FormWrapper)`
justify-content: center;
padding: 0 143px;
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import styled from 'styled-components'
import { FormRow, FormWrapper } from '../../form'
import { Stepper } from '@/components/stepper/Stepper'
import { Colors } from '@/styles/colors'
import { ClockIcon } from '@/components/icons'
import { Button } from '@/components/buttons'

const gitcoinScoreSteps = [
{
default: {
name: `Sending request`,
},
failed: {
name: 'Request failed',
},
},
{
default: {
name: 'Signing the message',
},
failed: {
name: 'Signing message failed',
},
},
{
default: {
name: 'Obtaining the score',
},
failed: {
name: 'Obtaining the score failed',
},
},
]

export const CheckGitcoinScore = () => {
return (
<Wrapper>
<Row>
<ClockIcon size={38} />
<StepperHeader>Checking Your Score</StepperHeader>
</Row>
<FormRow>
<span>It will take about 1 minute. Please stay on this page.</span>
</FormRow>
<Stepper steps={gitcoinScoreSteps} currentStep={1} isFailed={false} />
<Button>Sign Again</Button>
</Wrapper>
)
}

const Wrapper = styled(FormWrapper)`
justify-content: center;
gap: 16px;
padding: 0 143px;
`

const Row = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 16px;
`

const StepperHeader = styled.h3`
color: ${Colors.Black};
`
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react'
import { CheckGitcoinPassword } from './CheckGitcoinPassword'
import { CheckGitcoinScore } from './CheckingGitcoinScore'

enum GitcoinState {
INITIAL_PAGE,
Expand All @@ -9,12 +10,14 @@ enum GitcoinState {
}

export const GitcoinFlow = () => {
const [gitcoinState] = useState<GitcoinState>(GitcoinState.INITIAL_PAGE)
const [gitcoinState] = useState<GitcoinState>(GitcoinState.CHECKING_SCORE)

switch (gitcoinState) {
case GitcoinState.INITIAL_PAGE:
return <CheckGitcoinPassword />

case GitcoinState.CHECKING_SCORE:
return <CheckGitcoinScore />
default:
return <CheckGitcoinPassword />
}
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/src/styles/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const Colors = {
Transparent: 'transparent',
Porcelain: '#E7EAF3',
Mystic: '#D0D6E6',
Pink: '#FADAFA',
}

export const hexOpacity = (color: string, opacity: number) => {
Expand Down