mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-31 12:14:30 +01:00
feat: category page, some improvments for naming & project structure
This commit is contained in:
BIN
public/assets/images/header-2.jfif
Normal file
BIN
public/assets/images/header-2.jfif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/images/header.jpg
Normal file
BIN
public/assets/images/header.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 512 KiB |
@@ -6,7 +6,7 @@ import ProjectCardMiniSkeleton from './ProjectCardMini.Skeleton';
|
||||
|
||||
|
||||
export default {
|
||||
title: 'Explore Page/Project Card Mini',
|
||||
title: 'Projects/Project Card Mini',
|
||||
component: ProjectCardMini,
|
||||
|
||||
} as ComponentMeta<typeof ProjectCardMini>;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MdLocalFireDepartment } from "react-icons/md";
|
||||
import { ProjectCard } from "../../../utils/interfaces";
|
||||
import { ProjectCard } from "src/utils/interfaces";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -9,7 +9,7 @@ interface Props {
|
||||
|
||||
export default function ProjectCardMini({ project, onClick }: Props) {
|
||||
return (
|
||||
<div className="bg-gray-25 select-none px-16 py-16 flex w-[296px] gap-16 border border-gray-200 rounded-10 hover:cursor-pointer hover:bg-gray-100" onClick={() => onClick(project.id)}>
|
||||
<div className="bg-gray-25 select-none px-16 py-16 flex min-w-[296px] gap-16 border border-gray-200 rounded-10 hover:cursor-pointer hover:bg-gray-100" onClick={() => onClick(project.id)}>
|
||||
<img src={project.thumbnail_image} alt={project.title} draggable="false" className="flex-shrink-0 w-80 h-80 bg-gray-200 border-0 rounded-8"></img>
|
||||
<div className="justify-around items-start min-w-0">
|
||||
<p className="text-body4 w-full font-bold overflow-ellipsis overflow-hidden whitespace-nowrap">{project.title}</p>
|
||||
1
src/pages/CategoryPage/CategoryPage.tsx
Normal file
1
src/pages/CategoryPage/CategoryPage.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { }
|
||||
23
src/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx
Normal file
23
src/pages/CategoryPage/HeaderImage/HeaderImage.stories.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import HeaderImage from './HeaderImage';
|
||||
|
||||
export default {
|
||||
title: 'Pages/Category/Header Image',
|
||||
component: HeaderImage,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof HeaderImage>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof HeaderImage> = (args) => <HeaderImage {...args} ></HeaderImage>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
title: 'Art & Collectibles',
|
||||
apps_count: 44,
|
||||
img: '/assets/images/header-2.jfif'
|
||||
}
|
||||
|
||||
|
||||
24
src/pages/CategoryPage/HeaderImage/HeaderImage.tsx
Normal file
24
src/pages/CategoryPage/HeaderImage/HeaderImage.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import { FiArrowLeft } from 'react-icons/fi'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
apps_count: number
|
||||
img: string
|
||||
}
|
||||
|
||||
export default function HeaderImage({ title, apps_count, img }: Props) {
|
||||
return (
|
||||
<div className='h-[280px] rounded-20 overflow-hidden relative flex flex-col justify-center items-center gap-8'>
|
||||
<img src={img} alt={`${title} cover`} className='absolute inset-0 w-full h-full object-cover z-[-1]' />
|
||||
<div className='absolute inset-0 w-full h-full bg-black bg-opacity-50 z-[-1]' />
|
||||
<button className="w-[48px] h-[48px] bg-white absolute top-24 left-24 md:top-1/2 md:left-40 md:-translate-y-1/2 rounded-full hover:bg-gray-200 text-center" onClick={() => { }}><FiArrowLeft className=' inline-block text-body2 lg:text-body1' /></button>
|
||||
<h1
|
||||
className='text-white text-body1 md:text-[40px]'
|
||||
>{title}</h1>
|
||||
<p
|
||||
className='text-white text-body4'
|
||||
>{apps_count} apps</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx
Normal file
21
src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.stories.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import ProjectsGrid from './ProjectsGrid';
|
||||
|
||||
export default {
|
||||
title: 'Pages/Category/Projects Grid',
|
||||
component: ProjectsGrid,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof ProjectsGrid>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof ProjectsGrid> = (args) => <ProjectsGrid {...args} ></ProjectsGrid>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
|
||||
}
|
||||
|
||||
|
||||
15
src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx
Normal file
15
src/pages/CategoryPage/ProjectsGrid/ProjectsGrid.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import ProjectCardMini from 'src/Components/Cards/ProjectCardMini/ProjectCardMini'
|
||||
import mockData from 'src/api/mockData.json'
|
||||
|
||||
export default function ProjectsGrid() {
|
||||
return (
|
||||
<div style={{
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(296px, 1fr))',
|
||||
display: 'grid',
|
||||
gridGap: '24px',
|
||||
}}>
|
||||
{Array(30).fill(0).map((_, idx) => <ProjectCardMini key={idx} project={mockData.projectsCards[0]} onClick={() => { }} />)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import ProjectCardMiniSkeleton from "../ProjectCardMini/ProjectCardMini.Skeleton";
|
||||
import ProjectCardMiniSkeleton from "src/Components/Cards/ProjectCardMini/ProjectCardMini.Skeleton";
|
||||
import Skeleton from "react-loading-skeleton";
|
||||
|
||||
export default function ProjectsRowSkeleton() {
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { ReactElement, useRef, useState } from "react";
|
||||
import { ProjectCard } from "../../../utils/interfaces";
|
||||
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { ProjectCard } from "src/utils/interfaces";
|
||||
import Carousel from 'react-multi-carousel';
|
||||
import { MdArrowRight, MdDoubleArrow, } from 'react-icons/md';
|
||||
import { useAppDispatch } from "../../../utils/hooks";
|
||||
import { openModal } from "../../../redux/features/modals.slice";
|
||||
import ProjectCardMini from "../ProjectCardMini/ProjectCardMini";
|
||||
import { MdDoubleArrow, } from 'react-icons/md';
|
||||
import { useAppDispatch } from "src/utils/hooks";
|
||||
import { openModal } from "src/redux/features/modals.slice";
|
||||
import ProjectCardMini from "src/Components/Cards/ProjectCardMini/ProjectCardMini";
|
||||
import { useResizeListener } from 'src/utils/hooks'
|
||||
import { IoIosArrowBack, IoIosArrowForward } from "react-icons/io";
|
||||
import './style.css';
|
||||
|
||||
|
||||
interface Props {
|
||||
title: string | ReactNode,
|
||||
categoryId: string,
|
||||
projects: ProjectCard[]
|
||||
}
|
||||
|
||||
const responsive = {
|
||||
all: {
|
||||
@@ -29,23 +33,35 @@ function calcNumItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
interface Props { title: string | ReactElement, categoryId: string, projects: ProjectCard[] }
|
||||
|
||||
|
||||
export default function ProjectsRow({ title, categoryId, projects }: Props) {
|
||||
|
||||
const [carouselItmsCnt, setCarouselItmsCnt] = useState(calcNumItems);
|
||||
const dispatch = useAppDispatch()
|
||||
let drag = useRef(false);
|
||||
|
||||
responsive.all.items = carouselItmsCnt
|
||||
|
||||
let drag = useRef(false);
|
||||
|
||||
document.addEventListener('mousedown', () => drag.current = false);
|
||||
document.addEventListener('mousemove', () => drag.current = true);
|
||||
useEffect(() => {
|
||||
const mousedownListener = () => drag.current = false
|
||||
const mousemoveListener = () => drag.current = true
|
||||
|
||||
document.addEventListener('mousedown', mousedownListener);
|
||||
document.addEventListener('mousemove', mousemoveListener);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', mousedownListener);
|
||||
document.removeEventListener('mousemove', mousemoveListener);
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
|
||||
const handleClick = (projectId: string) => {
|
||||
if (!drag.current)
|
||||
dispatch(openModal({ Modal: "ProjectCard", props: { projectId } }))
|
||||
dispatch(openModal({ Modal: "ProjectDetailsCard", props: { projectId } }))
|
||||
}
|
||||
|
||||
useResizeListener(() => {
|
||||
@@ -57,7 +73,7 @@ export default function ProjectsRow({ title, categoryId, projects }: Props) {
|
||||
|
||||
|
||||
return (
|
||||
<div id={title.toString().toLowerCase()} className='mb-48'>
|
||||
<div className='mb-48'>
|
||||
<h3 className="font-bolder text-body3 mb-24 px-32">{title}
|
||||
<span>
|
||||
<MdDoubleArrow className='text-gray-200 ml-8 hover:cursor-pointer align-bottom transform scale-y-110 scale-x-125 origin-left' onClick={() => {
|
||||
@@ -85,7 +101,9 @@ export default function ProjectsRow({ title, categoryId, projects }: Props) {
|
||||
}
|
||||
>
|
||||
{projects.map((project, idx) =>
|
||||
<ProjectCardMini key={idx} project={project} onClick={handleClick} />
|
||||
<div key={project.id} className='max-w-[296px]'>
|
||||
<ProjectCardMini project={project} onClick={handleClick} />
|
||||
</div>
|
||||
)}
|
||||
</Carousel>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import Claim_CopySignatureCard from './Claim_CopySignatureCard';
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Claim/Copy Signature Card',
|
||||
title: 'Projects/Claim/Copy Signature Card',
|
||||
component: Claim_CopySignatureCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
|
||||
@@ -5,7 +5,7 @@ import Claim_FundWithdrawCard from './Claim_FundWithdrawCard';
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Claim/Fund Withdraw Card',
|
||||
title: 'Projects/Claim/Fund Withdraw Card',
|
||||
component: Claim_FundWithdrawCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
|
||||
@@ -5,7 +5,7 @@ import Claim_GenerateSignatureCard from './Claim_GenerateSignatureCard';
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Claim/Generate Signature Card',
|
||||
title: 'Projects/Claim/Generate Signature Card',
|
||||
component: Claim_GenerateSignatureCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
|
||||
@@ -5,7 +5,7 @@ import Claim_SubmittedCard from './Claim_SubmittedCard';
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Claim/Submitted Card',
|
||||
title: 'Projects/Claim/Submitted Card',
|
||||
component: Claim_SubmittedCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import ProjectCard from './ProjectCard';
|
||||
import ProjectCardSkeleton from './ProjectCard.Skeleton';
|
||||
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Project/Project Card',
|
||||
component: ProjectCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
} as ComponentMeta<typeof ProjectCard>;
|
||||
|
||||
const Template: ComponentStory<typeof ProjectCard> = (args) => <ProjectCard {...args} />;
|
||||
|
||||
export const Default = Template.bind({
|
||||
});
|
||||
|
||||
Default.args = {
|
||||
projectId: '3'
|
||||
}
|
||||
|
||||
|
||||
|
||||
const LoadingTemplate: ComponentStory<typeof ProjectCardSkeleton> = (args) => <ProjectCardSkeleton {...args} />;
|
||||
export const LoadingState = LoadingTemplate.bind({})
|
||||
@@ -9,7 +9,7 @@ import { useAppSelector } from 'src/utils/hooks';
|
||||
interface Props extends ModalCard {
|
||||
}
|
||||
|
||||
export default function ProjectCardSkeleton({ onClose, direction, ...props }: Props) {
|
||||
export default function ProjectDetailsCardSkeleton({ onClose, direction, ...props }: Props) {
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import ProjectDetailsCard from './ProjectDetailsCard';
|
||||
import ProjectDetailsCardSkeleton from './ProjectDetailsCard.Skeleton';
|
||||
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Project/Project Details Card',
|
||||
component: ProjectDetailsCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
} as ComponentMeta<typeof ProjectDetailsCard>;
|
||||
|
||||
const Template: ComponentStory<typeof ProjectDetailsCard> = (args) => <ProjectDetailsCard {...args} />;
|
||||
|
||||
export const Default = Template.bind({
|
||||
});
|
||||
|
||||
Default.args = {
|
||||
projectId: '3'
|
||||
}
|
||||
|
||||
|
||||
|
||||
const LoadingTemplate: ComponentStory<typeof ProjectDetailsCardSkeleton> = (args) => <ProjectDetailsCardSkeleton {...args} />;
|
||||
export const LoadingState = LoadingTemplate.bind({})
|
||||
@@ -8,8 +8,8 @@ import { setProject } from 'src/redux/features/project.slice';
|
||||
import Button from 'src/Components/Button/Button';
|
||||
import { PROJECT_BY_ID_QUERY, PROJECT_BY_ID_RES, PROJECT_BY_ID_VARS } from './query'
|
||||
import { AiFillThunderbolt } from 'react-icons/ai';
|
||||
import ProjectCardSkeleton from './ProjectCard.Skeleton'
|
||||
import TipButton from 'src/Components/TipButton/TipButton';
|
||||
import ProjectCardSkeleton from './ProjectDetailsCard.Skeleton'
|
||||
import VoteButton from 'src/pages/ProjectPage/VoteButton/VoteButton';
|
||||
import { Wallet_Service } from 'src/services'
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ interface Props extends ModalCard {
|
||||
projectId: string
|
||||
}
|
||||
|
||||
export default function ProjectCard({ onClose, direction, projectId, ...props }: Props) {
|
||||
export default function ProjectDetailsCard({ onClose, direction, projectId, ...props }: Props) {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -46,15 +46,15 @@ export default function ProjectCard({ onClose, direction, projectId, ...props }:
|
||||
Wallet_Service.connectWallet()
|
||||
}
|
||||
|
||||
const onTip = (tip?: number) => {
|
||||
const onVote = (votes?: number) => {
|
||||
|
||||
if (!isWalletConnected) {
|
||||
dispatch(scheduleModal({ Modal: 'TipCard', props: { tipValue: tip, projectId: project.id } }))
|
||||
dispatch(scheduleModal({ Modal: 'VoteCard', props: { initVotes: votes, projectId: project.id } }))
|
||||
dispatch(openModal({
|
||||
Modal: 'Login_ScanningWalletCard'
|
||||
}))
|
||||
} else
|
||||
dispatch(openModal({ Modal: 'TipCard', props: { tipValue: tip, projectId: project.id } }))
|
||||
dispatch(openModal({ Modal: 'VoteCard', props: { initVotes: votes, projectId: project.id } }))
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ export default function ProjectCard({ onClose, direction, projectId, ...props }:
|
||||
<div className="flex-shrink-0 hidden md:flex ml-auto gap-16">
|
||||
<Button color='primary' size='md' className=" my-16" href={project.website} newTab >Visit <BsJoystick /></Button>
|
||||
{isWalletConnected ?
|
||||
<TipButton onTip={onTip} />
|
||||
<VoteButton onVote={onVote} />
|
||||
:
|
||||
<Button onClick={onConnectWallet} size='md' className="border border-gray-200 bg-gray-100 hover:bg-gray-50 active:bg-gray-100 my-16"><AiFillThunderbolt className='inline-block text-thunder transform scale-125' /> Connect Wallet to Vote</Button>
|
||||
}
|
||||
@@ -108,7 +108,7 @@ export default function ProjectCard({ onClose, direction, projectId, ...props }:
|
||||
<div className="md:hidden">
|
||||
<Button color='primary' size='md' fullWidth href={project.website} newTab className="w-full mt-24 mb-16">Visit <BsJoystick /></Button>
|
||||
{isWalletConnected ?
|
||||
<TipButton fullWidth onTip={onTip} />
|
||||
<VoteButton fullWidth onVote={onVote} />
|
||||
:
|
||||
<Button size='md' fullWidth className="bg-gray-200 hover:bg-gray-100 mb-24" onClick={onConnectWallet}><AiFillThunderbolt className='inline-block text-thunder transform scale-125' /> Connect Wallet to Vote</Button>
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import TipButton from './TipButton';
|
||||
import VoteButton from './VoteButton';
|
||||
import { centerDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Shared/Tip Button',
|
||||
component: TipButton,
|
||||
title: 'Projects/Tip Button',
|
||||
component: VoteButton,
|
||||
decorators: [
|
||||
centerDecorator
|
||||
]
|
||||
} as ComponentMeta<typeof TipButton>;
|
||||
} as ComponentMeta<typeof VoteButton>;
|
||||
|
||||
const Template: ComponentStory<typeof TipButton> = (args) => <TipButton onTip={() => { }} />;
|
||||
const Template: ComponentStory<typeof VoteButton> = (args) => <VoteButton onVote={() => { }} />;
|
||||
|
||||
export const Default = Template.bind({});
|
||||
|
||||
@@ -3,7 +3,7 @@ import Button from 'src/Components/Button/Button'
|
||||
import { useAppSelector, usePressHolder } from 'src/utils/hooks'
|
||||
import _throttle from 'lodash.throttle'
|
||||
import { ComponentProps, useRef, useState } from 'react'
|
||||
import './tipbutton.style.css'
|
||||
import './vote-button.style.css'
|
||||
import { random, randomItem } from 'src/utils/helperFunctions'
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ interface Particle {
|
||||
}
|
||||
|
||||
type Props = {
|
||||
onTip: (tip: number) => void
|
||||
onVote: (Vote: number) => void
|
||||
} & Omit<ComponentProps<typeof Button>, 'children'>
|
||||
|
||||
export default function TipButton({ onTip = () => { }, ...props }: Props) {
|
||||
const [tipCnt, setTipCnt] = useState(0)
|
||||
const tipCntRef = useRef(0);
|
||||
export default function VoteButton({ onVote = () => { }, ...props }: Props) {
|
||||
const [voteCnt, setVoteCnt] = useState(0)
|
||||
const voteCntRef = useRef(0);
|
||||
const [sparks, setSparks] = useState<Particle[]>([]);
|
||||
const [wasActive, setWasActive] = useState(false);
|
||||
|
||||
@@ -30,10 +30,10 @@ export default function TipButton({ onTip = () => { }, ...props }: Props) {
|
||||
|
||||
|
||||
const { onPressDown, onPressUp } = usePressHolder(_throttle(() => {
|
||||
const _incStep = (Math.ceil((tipCnt + 1) / 10) + 1) ** 2 * 10;
|
||||
setTipCnt(s => {
|
||||
const _incStep = (Math.ceil((voteCnt + 1) / 10) + 1) ** 2 * 10;
|
||||
setVoteCnt(s => {
|
||||
const newValue = s + _incStep;
|
||||
tipCntRef.current = newValue;
|
||||
voteCntRef.current = newValue;
|
||||
return newValue;
|
||||
})
|
||||
|
||||
@@ -70,14 +70,14 @@ export default function TipButton({ onTip = () => { }, ...props }: Props) {
|
||||
setWasActive(false);
|
||||
if (event?.preventDefault) event.preventDefault();
|
||||
onPressUp();
|
||||
if (tipCnt === 0)
|
||||
onTip(10);
|
||||
if (voteCnt === 0)
|
||||
onVote(10);
|
||||
else
|
||||
setTimeout(() => {
|
||||
setSparks([]);
|
||||
onTip(tipCntRef.current);
|
||||
setTipCnt(0);
|
||||
tipCntRef.current = 0;
|
||||
onVote(voteCntRef.current);
|
||||
setVoteCnt(0);
|
||||
voteCntRef.current = 0;
|
||||
}, 500)
|
||||
}
|
||||
|
||||
@@ -91,17 +91,17 @@ export default function TipButton({ onTip = () => { }, ...props }: Props) {
|
||||
onTouchEnd={handlePressUp}
|
||||
size='md'
|
||||
color='none'
|
||||
className="tip-button border relative 100 my-16 noselect"
|
||||
className="vote-button border relative 100 my-16 noselect"
|
||||
style={{
|
||||
"--scale": tipCnt,
|
||||
"--scale": voteCnt,
|
||||
} as any}
|
||||
{...props}
|
||||
>
|
||||
Hold To Vote !!! <MdLocalFireDepartment className='text-fire' />
|
||||
|
||||
<span
|
||||
className='tip-counter'
|
||||
>{tipCnt}</span>
|
||||
className='Vote-counter'
|
||||
>{voteCnt}</span>
|
||||
|
||||
<div
|
||||
className='spark'
|
||||
@@ -1,17 +1,17 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import TipCard from './TipCard';
|
||||
import VoteCard from './VoteCard';
|
||||
|
||||
import { ModalsDecorator } from 'src/utils/storybookDecorators'
|
||||
|
||||
export default {
|
||||
title: 'Tip/Tip Card',
|
||||
component: TipCard,
|
||||
title: 'Components/Cards/Vote Card',
|
||||
component: VoteCard,
|
||||
|
||||
decorators: [ModalsDecorator]
|
||||
} as ComponentMeta<typeof TipCard>;
|
||||
} as ComponentMeta<typeof VoteCard>;
|
||||
|
||||
const Template: ComponentStory<typeof TipCard> = (args) => <TipCard {...args} />;
|
||||
const Template: ComponentStory<typeof VoteCard> = (args) => <VoteCard {...args} />;
|
||||
|
||||
export const Default = Template.bind({});
|
||||
|
||||
@@ -9,6 +9,7 @@ import useWindowSize from "react-use/lib/useWindowSize";
|
||||
import Confetti from "react-confetti";
|
||||
import { Wallet_Service } from 'src/services';
|
||||
import styles from './style.module.css'
|
||||
import { CONFIRM_VOTE_QUERY, CONFIRM_VOTE_QUERY_RES_TYPE, VOTE_QUERY, VOTE_QUERY_RES_TYPE } from './query';
|
||||
|
||||
const defaultOptions = [
|
||||
{ text: '100 sat', value: 100 },
|
||||
@@ -27,36 +28,13 @@ enum PaymentStatus {
|
||||
CANCELED
|
||||
}
|
||||
|
||||
const VOTE = gql`
|
||||
mutation Mutation($projectId: Int!, $amountInSat: Int!) {
|
||||
vote(project_id: $projectId, amount_in_sat: $amountInSat) {
|
||||
id
|
||||
amount_in_sat
|
||||
payment_request
|
||||
payment_hash
|
||||
paid
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const CONFIRM_VOTE = gql`
|
||||
mutation Mutation($paymentRequest: String!, $preimage: String!) {
|
||||
confirmVote(payment_request: $paymentRequest, preimage: $preimage) {
|
||||
id
|
||||
amount_in_sat
|
||||
paid
|
||||
payment_hash
|
||||
payment_request
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props extends ModalCard {
|
||||
tipValue?: number;
|
||||
initVotes?: number;
|
||||
projectId: string
|
||||
}
|
||||
|
||||
export default function TipCard({ onClose, direction, tipValue, projectId, ...props }: Props) {
|
||||
export default function VoteCard({ onClose, direction, initVotes, projectId, ...props }: Props) {
|
||||
const { width, height } = useWindowSize()
|
||||
|
||||
const { isWalletConnected } = useAppSelector(state => ({
|
||||
@@ -65,10 +43,10 @@ export default function TipCard({ onClose, direction, tipValue, projectId, ...pr
|
||||
|
||||
|
||||
const [selectedOption, setSelectedOption] = useState(10);
|
||||
const [voteAmount, setVoteAmount] = useState<number>(tipValue ?? 10);
|
||||
const [voteAmount, setVoteAmount] = useState<number>(initVotes ?? 10);
|
||||
const [paymentStatus, setPaymentStatus] = useState<PaymentStatus>(PaymentStatus.DEFAULT);
|
||||
|
||||
const [vote, { data }] = useMutation(VOTE, {
|
||||
const [vote, { data }] = useMutation<VOTE_QUERY_RES_TYPE>(VOTE_QUERY, {
|
||||
onCompleted: async (votingData) => {
|
||||
try {
|
||||
setPaymentStatus(PaymentStatus.AWAITING_PAYMENT);
|
||||
@@ -97,7 +75,7 @@ export default function TipCard({ onClose, direction, tipValue, projectId, ...pr
|
||||
}
|
||||
});
|
||||
|
||||
const [confirmVote, { data: confirmedVoteData }] = useMutation(CONFIRM_VOTE, {
|
||||
const [confirmVote, { data: confirmedVoteData }] = useMutation<CONFIRM_VOTE_QUERY_RES_TYPE>(CONFIRM_VOTE_QUERY, {
|
||||
refetchQueries: [
|
||||
'Project',
|
||||
'AllCategoriesProjects'
|
||||
45
src/pages/ProjectPage/VoteCard/query.ts
Normal file
45
src/pages/ProjectPage/VoteCard/query.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { gql } from "@apollo/client";
|
||||
|
||||
export const VOTE_QUERY = gql`
|
||||
mutation Mutation($projectId: Int!, $amountInSat: Int!) {
|
||||
vote(project_id: $projectId, amount_in_sat: $amountInSat) {
|
||||
id
|
||||
amount_in_sat
|
||||
payment_request
|
||||
payment_hash
|
||||
paid
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export type VOTE_QUERY_RES_TYPE = {
|
||||
vote: {
|
||||
id: number;
|
||||
amount_in_sat: number;
|
||||
payment_request: string;
|
||||
payment_hash: string;
|
||||
paid: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export const CONFIRM_VOTE_QUERY = gql`
|
||||
mutation Mutation($paymentRequest: String!, $preimage: String!) {
|
||||
confirmVote(payment_request: $paymentRequest, preimage: $preimage) {
|
||||
id
|
||||
amount_in_sat
|
||||
paid
|
||||
payment_hash
|
||||
payment_request
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export type CONFIRM_VOTE_QUERY_RES_TYPE = {
|
||||
confirmVote: {
|
||||
id: number;
|
||||
amount_in_sat: number;
|
||||
paid: boolean;
|
||||
payment_hash: string;
|
||||
payment_request: string;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import Login_ExternalWalletCard from "src/Components/Modals/Login/Login_External
|
||||
import Login_NativeWalletCard from "src/Components/Modals/Login/Login_NativeWalletCard";
|
||||
import Login_SuccessCard from "src/Components/Modals/Login/Login_SuccessCard";
|
||||
import Login_ScanningWalletCard from "src/Components/Modals/Login/Login_ScanningWalletCard";
|
||||
import ProjectCard from "src/pages/ProjectPage/ProjectCard/ProjectCard";
|
||||
import TipCard from "src/pages/ProjectPage/Tip/TipCard";
|
||||
import ProjectDetailsCard from "src/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard";
|
||||
import VoteCard from "src/pages/ProjectPage/VoteCard/VoteCard";
|
||||
import Claim_SubmittedCard from "src/pages/ProjectPage/ClaimProject/Claim_SubmittedCard";
|
||||
import Claim_FundWithdrawCard from "src/pages/ProjectPage/ClaimProject/Claim_FundWithdrawCard";
|
||||
import { ModalCard } from "src/Components/Modals/ModalsContainer/ModalsContainer";
|
||||
@@ -22,12 +22,12 @@ export enum Direction {
|
||||
|
||||
|
||||
export const ALL_MODALS = {
|
||||
ProjectCard,
|
||||
ProjectDetailsCard,
|
||||
Login_ScanningWalletCard,
|
||||
Login_NativeWalletCard,
|
||||
Login_SuccessCard,
|
||||
Login_ExternalWalletCard,
|
||||
TipCard,
|
||||
VoteCard,
|
||||
Claim_GenerateSignatureCard,
|
||||
Claim_CopySignatureCard,
|
||||
Claim_SubmittedCard,
|
||||
@@ -117,7 +117,7 @@ export const modalSlice = createSlice({
|
||||
let props: any = {};
|
||||
if ('props' in action.payload) props = { ...action.payload.props }
|
||||
|
||||
props.isPageModal = action.payload.Modal === 'ProjectCard';
|
||||
props.isPageModal = action.payload.Modal === 'ProjectDetailsCard';
|
||||
|
||||
state.openModals.push({
|
||||
Modal: action.payload.Modal,
|
||||
@@ -136,7 +136,7 @@ export const modalSlice = createSlice({
|
||||
let props: any = {};
|
||||
if ('props' in action.payload) props = { ...action.payload.props }
|
||||
|
||||
props.isPageModal = action.payload.Modal === 'ProjectCard';
|
||||
props.isPageModal = action.payload.Modal === 'ProjectDetailsCard';
|
||||
|
||||
state.openModals.push({
|
||||
Modal: action.payload.Modal,
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
export interface AllCategoriesData {
|
||||
allCategories: ProjectCategory[];
|
||||
}
|
||||
|
||||
export interface ProjectCategory {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface ProjectCard {
|
||||
id: string;
|
||||
title: string;
|
||||
thumbnail_image: string;
|
||||
category: ProjectCategory;
|
||||
votes_count: number;
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export type Image = string;
|
||||
|
||||
export interface Project {
|
||||
id: string;
|
||||
title: string;
|
||||
category: ProjectCategory;
|
||||
website?: string;
|
||||
description: string;
|
||||
tags: Tag[];
|
||||
cover_image: Image;
|
||||
thumbnail_image: Image;
|
||||
screenShots: Image[];
|
||||
votes_count: number;
|
||||
}
|
||||
4
src/utils/interfaces/index.ts
Normal file
4
src/utils/interfaces/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './misc.interfaces'
|
||||
export * from './project.interfaces'
|
||||
|
||||
|
||||
8
src/utils/interfaces/misc.interfaces.ts
Normal file
8
src/utils/interfaces/misc.interfaces.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
export interface Tag {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export type Image = string;
|
||||
31
src/utils/interfaces/project.interfaces.ts
Normal file
31
src/utils/interfaces/project.interfaces.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Image, Tag } from ".";
|
||||
|
||||
export interface Project {
|
||||
id: string;
|
||||
title: string;
|
||||
category: ProjectCategory;
|
||||
website?: string;
|
||||
description: string;
|
||||
tags: Tag[];
|
||||
cover_image: Image;
|
||||
thumbnail_image: Image;
|
||||
screenShots: Image[];
|
||||
votes_count: number;
|
||||
}
|
||||
|
||||
export interface ProjectCategory {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface ProjectCard {
|
||||
id: string;
|
||||
title: string;
|
||||
thumbnail_image: string;
|
||||
category: ProjectCategory;
|
||||
votes_count: number;
|
||||
}
|
||||
|
||||
interface AllCategoriesData {
|
||||
allCategories: ProjectCategory[];
|
||||
}
|
||||
Reference in New Issue
Block a user