From 72081ba0db3c35a15fa3cfd3d55597d8d5548c3a Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 17:49:30 +0100 Subject: [PATCH 1/7] chore: add bounty card --- cypress/e2e/62_BountyCard.cy.ts | 40 +++++ .../WorkSpacePlanner/BountyCard/index.tsx | 144 ++++++++++++++++++ src/people/WorkSpacePlanner/index.tsx | 10 +- src/store/interface.ts | 1 + 4 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 cypress/e2e/62_BountyCard.cy.ts create mode 100644 src/people/WorkSpacePlanner/BountyCard/index.tsx diff --git a/cypress/e2e/62_BountyCard.cy.ts b/cypress/e2e/62_BountyCard.cy.ts new file mode 100644 index 00000000..f0dbc97d --- /dev/null +++ b/cypress/e2e/62_BountyCard.cy.ts @@ -0,0 +1,40 @@ +// cypress/e2e/bountyCard.spec.js +describe('BountyCardComponent', () => { + beforeEach(() => { + cy.viewport(500, 800); + }); + + it('renders correctly with given props', () => { + const props = { + id: 'bounty123', + title: 'Test Bounty Card', + features: { name: 'Feature A' }, + phase: { name: 'Phase 1' }, + assigneePic: 'https://via.placeholder.com/40', + workspace: { name: 'Workspace X' }, + onclick: cy.stub() + }; + + cy.get('h3').should('contain', props.title); + cy.get('span').should('contain', props.features.name); + cy.get('span').should('contain', props.phase.name); + cy.get('span').should('contain', props.workspace.name); + cy.get('img').should('have.attr', 'src', props.assigneePic); + }); + + it('triggers onclick when title is clicked', () => { + const onclick = cy.stub(); + const props = { + id: 'bounty123', + title: 'Clickable Title', + features: {}, + phase: {}, + assignee_img: '', + workspace: {}, + onclick + }; + + cy.get('h3').click(); + cy.wrap(onclick).should('be.calledWith', 'bounty123'); + }); +}); diff --git a/src/people/WorkSpacePlanner/BountyCard/index.tsx b/src/people/WorkSpacePlanner/BountyCard/index.tsx new file mode 100644 index 00000000..be0a836c --- /dev/null +++ b/src/people/WorkSpacePlanner/BountyCard/index.tsx @@ -0,0 +1,144 @@ +import React from 'react'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; +import { BountyCard } from 'store/interface'; +import { colors } from '../../../config'; + +const Card = styled.div` + width: 384px; + border-radius: 8px; + padding: 16px; + margin-bottom: 16px; + display: flex; + flex-direction: column; + background-color: ${colors.light.grayish.G950}; + transition: + box-shadow 0.3s ease, + border 0.3s ease; + + &:hover { + border: 1px solid ${colors.light.light_blue100}; + box-shadow: 0 0 5px 1px ${colors.light.light_blue200}; + } +`; + +const Row = styled.div` + display: flex; + justify-content: flex-start; + align-items: center; + font-size: 14px; + font-weight: 400; + margin-bottom: 8px; + color: ${colors.light.text2}; + + span { + margin-right: 20%; + white-space: nowrap; + } + + .span { + margin-left: auto; + justify-content: flex-end; + } +`; + +const Header = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 16px; +`; + +const CardTitle = styled.h3` + font-size: 20px; + font-weight: 700; + padding-right: 16px; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: pointer; + text-align: left; + color: ${colors.light.text1}; + + &:hover { + color: ${colors.light.primaryColor}; + } +`; + +const AssignerPic = styled.div` + width: 40px; + height: 40px; + border-radius: 50%; + overflow: hidden; + background-color: ${colors.light.red1}; + display: flex; + justify-content: center; + align-items: center; + font-size: 14px; + color: white; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +`; + +interface BountyCardProps extends BountyCard { + onclick: (bountyId: string) => void; +} + +const BountyCardComp = ({ + id, + title, + features, + phase, + assigneePic, + workspace, + onclick +}: BountyCardProps) => { + const handleTitleClick = ( + event: React.MouseEvent | React.KeyboardEvent + ) => { + event.preventDefault(); + onclick(id); + }; + + return ( + +
+ {title} + {assigneePic ? Assigner : 'Pic'} +
+ + + {features?.name ?? 'No Feature'} + {phase?.name ?? 'No Phase'} + + + {id} + {workspace?.name ?? 'No Workspace'} + Paid? + +
+ ); +}; + +BountyCardComp.propTypes = { + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + features: PropTypes.shape({ + name: PropTypes.string + }), + phase: PropTypes.shape({ + name: PropTypes.string + }), + assignee_img: PropTypes.string, + workspace: PropTypes.shape({ + name: PropTypes.string + }), + onclick: PropTypes.func.isRequired +}; + +export default BountyCardComp; diff --git a/src/people/WorkSpacePlanner/index.tsx b/src/people/WorkSpacePlanner/index.tsx index 5f91ecf2..5bc5712f 100644 --- a/src/people/WorkSpacePlanner/index.tsx +++ b/src/people/WorkSpacePlanner/index.tsx @@ -5,9 +5,11 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import styled from 'styled-components'; import { useBountyCardStore } from 'store/bountyCard'; import { BountyCard } from 'store/interface'; +import history from 'config/history'; import { useStores } from '../../store'; import { colors } from '../../config'; import { WorkspacePlannerHeader } from './WorkspacePlannerHeader'; +import BountyCardComp from './BountyCard'; const PlannerContainer = styled.div` padding: 0; @@ -67,6 +69,10 @@ const WorkspacePlanner = () => { ); } + const onclick = (bountyId: string) => { + history.push(`/bounty/${bountyId}`); + }; + return ( @@ -80,9 +86,7 @@ const WorkspacePlanner = () => { ) : ( {bountyCardStore.bountyCards.map((card: BountyCard) => ( -
  • - {card.title} -
  • + ))}
    )} diff --git a/src/store/interface.ts b/src/store/interface.ts index 3702f13a..6b3f563b 100644 --- a/src/store/interface.ts +++ b/src/store/interface.ts @@ -511,4 +511,5 @@ export interface BountyCard { features: Feature; phase: Phase; workspace: Workspace; + assigneePic: string; } From 3c86e52ebdbdd8655065a97e1e807a48902e3743 Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 17:51:23 +0100 Subject: [PATCH 2/7] chore: add bounty card --- src/people/WorkSpacePlanner/BountyCard/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/people/WorkSpacePlanner/BountyCard/index.tsx b/src/people/WorkSpacePlanner/BountyCard/index.tsx index be0a836c..d12b3d96 100644 --- a/src/people/WorkSpacePlanner/BountyCard/index.tsx +++ b/src/people/WorkSpacePlanner/BountyCard/index.tsx @@ -12,10 +12,6 @@ const Card = styled.div` display: flex; flex-direction: column; background-color: ${colors.light.grayish.G950}; - transition: - box-shadow 0.3s ease, - border 0.3s ease; - &:hover { border: 1px solid ${colors.light.light_blue100}; box-shadow: 0 0 5px 1px ${colors.light.light_blue200}; From 9be00692815141f9ee9044cdfca973395678bf46 Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 18:57:12 +0100 Subject: [PATCH 3/7] feat: cleanup cards --- .../WorkSpacePlanner/BountyCard/index.tsx | 127 +++++++++--------- src/people/WorkSpacePlanner/index.tsx | 1 - src/store/interface.ts | 2 +- 3 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/people/WorkSpacePlanner/BountyCard/index.tsx b/src/people/WorkSpacePlanner/BountyCard/index.tsx index d12b3d96..5446f437 100644 --- a/src/people/WorkSpacePlanner/BountyCard/index.tsx +++ b/src/people/WorkSpacePlanner/BountyCard/index.tsx @@ -1,44 +1,24 @@ import React from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; -import { BountyCard } from 'store/interface'; +import { BountyCard } from '../../../store/interface'; import { colors } from '../../../config'; -const Card = styled.div` +const truncate = (str: string, n: number) => (str.length > n ? `${str.substr(0, n - 1)}...` : str); + +const CardContainer = styled.div` width: 384px; + height: auto; border-radius: 8px; - padding: 16px; + padding: 16px 16px 0 16px; margin-bottom: 16px; display: flex; flex-direction: column; background-color: ${colors.light.grayish.G950}; - &:hover { - border: 1px solid ${colors.light.light_blue100}; - box-shadow: 0 0 5px 1px ${colors.light.light_blue200}; - } -`; - -const Row = styled.div` - display: flex; - justify-content: flex-start; - align-items: center; - font-size: 14px; - font-weight: 400; - margin-bottom: 8px; - color: ${colors.light.text2}; - - span { - margin-right: 20%; - white-space: nowrap; - } - - .span { - margin-left: auto; - justify-content: flex-end; - } + cursor: pointer; `; -const Header = styled.div` +const CardHeader = styled.div` display: flex; justify-content: space-between; align-items: center; @@ -46,17 +26,16 @@ const Header = styled.div` `; const CardTitle = styled.h3` - font-size: 20px; - font-weight: 700; + font-size: 22px; + font-weight: 600; + margin: 0; padding-right: 16px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; - cursor: pointer; text-align: left; - color: ${colors.light.text1}; - + cursor: pointer; &:hover { color: ${colors.light.primaryColor}; } @@ -81,60 +60,76 @@ const AssignerPic = styled.div` } `; +const Rows = styled.div` + display: flex; + justify-content: flex-start; + margin-bottom: 8px; + font-size: 14px; + color: ${colors.light.text2}; + + span { + margin-right: 20%; + } + + .last-span { + margin-left: auto; + margin-right: 0; + } +`; + interface BountyCardProps extends BountyCard { onclick: (bountyId: string) => void; } -const BountyCardComp = ({ +const BountyCardComponent: React.FC = ({ id, title, features, phase, - assigneePic, + assignee_img, workspace, onclick -}: BountyCardProps) => { - const handleTitleClick = ( - event: React.MouseEvent | React.KeyboardEvent - ) => { - event.preventDefault(); - onclick(id); - }; +}: BountyCardProps) => ( + onclick(id)}> + + ) => e.stopPropagation()} + > + {title} + + {assignee_img ? Assigner : 'Pic'} + - return ( - -
    - {title} - {assigneePic ? Assigner : 'Pic'} -
    - - - {features?.name ?? 'No Feature'} - {phase?.name ?? 'No Phase'} - - - {id} - {workspace?.name ?? 'No Workspace'} - Paid? - -
    - ); -}; + + + {truncate(features?.name ?? 'No Feature', 4)} + + {phase?.name ?? 'No Phase'} + + + {id} + {workspace?.name ?? 'No Workspace'} + Paid? + +
    +); -BountyCardComp.propTypes = { +BountyCardComponent.propTypes = { id: PropTypes.string.isRequired, title: PropTypes.string.isRequired, features: PropTypes.shape({ name: PropTypes.string - }), + }) as PropTypes.Validator, phase: PropTypes.shape({ name: PropTypes.string - }), + }) as PropTypes.Validator, assignee_img: PropTypes.string, workspace: PropTypes.shape({ name: PropTypes.string - }), + }) as PropTypes.Validator, onclick: PropTypes.func.isRequired }; -export default BountyCardComp; +export default BountyCardComponent; diff --git a/src/people/WorkSpacePlanner/index.tsx b/src/people/WorkSpacePlanner/index.tsx index 5bc5712f..d932f281 100644 --- a/src/people/WorkSpacePlanner/index.tsx +++ b/src/people/WorkSpacePlanner/index.tsx @@ -78,7 +78,6 @@ const WorkspacePlanner = () => {

    Welcome to the new Workspace Planner

    -

    Bounty Cards

    {bountyCardStore.loading ? ( ) : bountyCardStore.error ? ( diff --git a/src/store/interface.ts b/src/store/interface.ts index 6b3f563b..b5460c34 100644 --- a/src/store/interface.ts +++ b/src/store/interface.ts @@ -511,5 +511,5 @@ export interface BountyCard { features: Feature; phase: Phase; workspace: Workspace; - assigneePic: string; + assignee_img?: string; } From 624c4fec5c9cd2441a64456a5b544d247bdc07c4 Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 19:01:27 +0100 Subject: [PATCH 4/7] chore: remove test --- cypress/e2e/62_BountyCard.cy.ts | 40 --------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 cypress/e2e/62_BountyCard.cy.ts diff --git a/cypress/e2e/62_BountyCard.cy.ts b/cypress/e2e/62_BountyCard.cy.ts deleted file mode 100644 index f0dbc97d..00000000 --- a/cypress/e2e/62_BountyCard.cy.ts +++ /dev/null @@ -1,40 +0,0 @@ -// cypress/e2e/bountyCard.spec.js -describe('BountyCardComponent', () => { - beforeEach(() => { - cy.viewport(500, 800); - }); - - it('renders correctly with given props', () => { - const props = { - id: 'bounty123', - title: 'Test Bounty Card', - features: { name: 'Feature A' }, - phase: { name: 'Phase 1' }, - assigneePic: 'https://via.placeholder.com/40', - workspace: { name: 'Workspace X' }, - onclick: cy.stub() - }; - - cy.get('h3').should('contain', props.title); - cy.get('span').should('contain', props.features.name); - cy.get('span').should('contain', props.phase.name); - cy.get('span').should('contain', props.workspace.name); - cy.get('img').should('have.attr', 'src', props.assigneePic); - }); - - it('triggers onclick when title is clicked', () => { - const onclick = cy.stub(); - const props = { - id: 'bounty123', - title: 'Clickable Title', - features: {}, - phase: {}, - assignee_img: '', - workspace: {}, - onclick - }; - - cy.get('h3').click(); - cy.wrap(onclick).should('be.calledWith', 'bounty123'); - }); -}); From 6b440903b894395e8b55e99436a711f241cc99a8 Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 19:08:32 +0100 Subject: [PATCH 5/7] chore: enable trucation for each field --- src/people/WorkSpacePlanner/BountyCard/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/people/WorkSpacePlanner/BountyCard/index.tsx b/src/people/WorkSpacePlanner/BountyCard/index.tsx index 5446f437..368597e8 100644 --- a/src/people/WorkSpacePlanner/BountyCard/index.tsx +++ b/src/people/WorkSpacePlanner/BountyCard/index.tsx @@ -106,11 +106,11 @@ const BountyCardComponent: React.FC = ({ {truncate(features?.name ?? 'No Feature', 4)} - {phase?.name ?? 'No Phase'} + {truncate(phase?.name ?? 'No Phase', 20)} {id} - {workspace?.name ?? 'No Workspace'} + {truncate(workspace?.name ?? 'No Workspace', 20)} Paid? From 2be100fbba4e5bbb84392cbd232bc4ffbbd8ba99 Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 19:11:52 +0100 Subject: [PATCH 6/7] chore: fix prettier errors --- src/people/WorkSpacePlanner/BountyCard/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/people/WorkSpacePlanner/BountyCard/index.tsx b/src/people/WorkSpacePlanner/BountyCard/index.tsx index 368597e8..00203019 100644 --- a/src/people/WorkSpacePlanner/BountyCard/index.tsx +++ b/src/people/WorkSpacePlanner/BountyCard/index.tsx @@ -110,7 +110,9 @@ const BountyCardComponent: React.FC = ({ {id} - {truncate(workspace?.name ?? 'No Workspace', 20)} + + {truncate(workspace?.name ?? 'No Workspace', 20)} + Paid? From d9131d6f87c1f3feb5e0b4e011ea3fce86ce89ee Mon Sep 17 00:00:00 2001 From: jordan-ae Date: Fri, 27 Dec 2024 21:58:08 +0100 Subject: [PATCH 7/7] chore: rerun cypress --- .../WorkSpacePlanner/BountyCard/index.tsx | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/people/WorkSpacePlanner/BountyCard/index.tsx b/src/people/WorkSpacePlanner/BountyCard/index.tsx index 00203019..403f60f7 100644 --- a/src/people/WorkSpacePlanner/BountyCard/index.tsx +++ b/src/people/WorkSpacePlanner/BountyCard/index.tsx @@ -60,16 +60,27 @@ const AssignerPic = styled.div` } `; -const Rows = styled.div` +const RowT = styled.div` display: flex; justify-content: flex-start; margin-bottom: 8px; font-size: 14px; color: ${colors.light.text2}; + gap: 1.5rem; - span { - margin-right: 20%; + .last-span { + margin-left: auto; + margin-right: 0; } +`; + +const RowB = styled.div` + display: flex; + justify-content: flex-start; + margin-bottom: 8px; + font-size: 14px; + color: ${colors.light.text2}; + gap: 4rem; .last-span { margin-left: auto; @@ -102,19 +113,19 @@ const BountyCardComponent: React.FC = ({ {assignee_img ? Assigner : 'Pic'} - + - {truncate(features?.name ?? 'No Feature', 4)} + {truncate(features?.name ?? 'No Feature', 10)} {truncate(phase?.name ?? 'No Phase', 20)} - - + + {id} {truncate(workspace?.name ?? 'No Workspace', 20)} Paid? - + );