From 85e6be25f590c960a5f496b2306c0be38f4a48b2 Mon Sep 17 00:00:00 2001 From: aliraza556 Date: Tue, 31 Dec 2024 20:17:38 +0500 Subject: [PATCH 1/2] feat: add bounty steps and featured sections to landing page --- .../BountyComponents/BountySteps.tsx | 70 ++++++++++++++++++ .../BountyComponents/FeaturedBounties.tsx | 74 +++++++++++++++++++ src/components/BountyComponents/index.tsx | 10 +++ src/pages/BountiesLandingPage/index.tsx | 2 + 4 files changed, 156 insertions(+) create mode 100644 src/components/BountyComponents/BountySteps.tsx create mode 100644 src/components/BountyComponents/FeaturedBounties.tsx create mode 100644 src/components/BountyComponents/index.tsx diff --git a/src/components/BountyComponents/BountySteps.tsx b/src/components/BountyComponents/BountySteps.tsx new file mode 100644 index 00000000..08dcafad --- /dev/null +++ b/src/components/BountyComponents/BountySteps.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import styled from 'styled-components'; +import { colors } from '../../config/colors'; + +const StepsContainer = styled.div` + display: flex; + flex-direction: column; + gap: 2px; + margin: 20px 0; +`; + +const StepItem = styled.div` + display: flex; + align-items: flex-start; + gap: 4px; + font-size: 16px; + margin-left: 2%; + color: ${colors.light.text1}; +`; + +const StepLabel = styled.span` + font-weight: 800; + font-size: 18px; +`; + +const StepText = styled.span` + font-weight: 500; +`; + +const StepTitle = styled.h6` + font-size: 20px; + font-family: 'Barlow'; + font-weight: 800; + color: ${colors.light.text1}; + margin-bottom: 20px; +`; + +interface Step { + text: string; +} + +const steps: Step[] = [ + { + text: 'Sign up for a Sphinx by clicking the Get Sphinx button!' + }, + { + text: 'Check out the open bounties, by clicking bounties!' + }, + { + text: 'Reach out to the bounty provider by clicking "I can help!"' + }, + { + text: 'Introduce yourself and get assigned' + }, + { + text: 'Compelte the work and get paid directly to your Sphinx Wallet!' + } +]; + +export const BountySteps: React.FC = () => ( + + If you want to earn bounties + {steps.map((step: Step, index: number) => ( + + {`Step ${index + 1}:`} + {step.text} + + ))} + +); diff --git a/src/components/BountyComponents/FeaturedBounties.tsx b/src/components/BountyComponents/FeaturedBounties.tsx new file mode 100644 index 00000000..2fab1a5e --- /dev/null +++ b/src/components/BountyComponents/FeaturedBounties.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import styled from 'styled-components'; +import { observer } from 'mobx-react-lite'; +import { colors } from '../../config/colors'; +import { bountyStore } from '../../store/bountyStore'; + +const FeaturedContainer = styled.div` + margin: 20px 0; +`; + +const FeaturedHeader = styled.div` + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 16px; + + h2 { + font-size: 18px; + font-weight: 600; + color: ${colors.light.text1}; + margin: 0; + } +`; + +const BountyCard = styled.div` + padding: 16px; + border: 1px solid ${colors.light.grayish.G900}; + border-radius: 8px; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + background: ${colors.light.grayish.G950}; + } +`; + +const BountyTitle = styled.h3` + font-size: 16px; + font-weight: 500; + color: ${colors.light.text1}; + margin: 0 0 8px 0; +`; + +const BountyMeta = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + color: ${colors.light.text2}; + font-size: 14px; +`; + +export const FeaturedBounties: React.FC = observer(() => { + const featuredBounty = bountyStore.getFeaturedBounty(); + return ( + + +

Featured Bounties

+
+ + {featuredBounty ? ( + (window.location.href = featuredBounty.url)}> + Bounty #{featuredBounty.bountyId} + + View Details + + + ) : ( +
+ No featured bounties at the moment +
+ )} +
+ ); +}); diff --git a/src/components/BountyComponents/index.tsx b/src/components/BountyComponents/index.tsx new file mode 100644 index 00000000..be2c6d2d --- /dev/null +++ b/src/components/BountyComponents/index.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { BountySteps } from './BountySteps'; +import { FeaturedBounties } from './FeaturedBounties'; + +export const BountyComponents = () => ( + <> + + + +); diff --git a/src/pages/BountiesLandingPage/index.tsx b/src/pages/BountiesLandingPage/index.tsx index d7dbcaac..2205fabe 100644 --- a/src/pages/BountiesLandingPage/index.tsx +++ b/src/pages/BountiesLandingPage/index.tsx @@ -6,6 +6,7 @@ import { colors } from '../../config/colors'; import { BountiesHeader, HeaderWrap, Leftheader } from '../tickets/style.ts'; import { BountyHeaderContent } from '../tickets/workspace/workspaceHeader/WorkspaceHeaderStyles.tsx'; import TopEarners from '../../components/common/TopEarners/index.tsx'; +import { BountyComponents } from '../../components/BountyComponents'; const BountiesLandingPage: React.FC = () => { const isMobile = useIsMobile(); @@ -103,6 +104,7 @@ const BountiesLandingPage: React.FC = () => { Building the modern marketplace for work. Complete a bounty and get paid in Bitcoin instantly! ⚡

+

Freedom to Earn!

From 4da7dc23bc2011bf204f9ad262d479edcd71ae57 Mon Sep 17 00:00:00 2001 From: aliraza556 Date: Wed, 1 Jan 2025 03:06:28 +0500 Subject: [PATCH 2/2] Implement Featured Bounties display --- src/bounties/BountyDescription.tsx | 35 +++++-- src/bounties/BountyPrice.tsx | 3 + src/bounties/BountyProfileView.tsx | 11 ++- src/bounties/interfaces.ts | 3 + .../BountyComponents/FeaturedBounties.tsx | 94 +++++++++++-------- src/pages/BountiesLandingPage/index.tsx | 6 +- src/people/interfaces.ts | 3 + .../utils/AssignedUnassignedBounties.tsx | 10 +- src/people/utils/NameTag.tsx | 7 +- src/people/widgetViews/WantedView.tsx | 4 +- src/people/widgetViews/WidgetSwitchViewer.tsx | 6 +- 11 files changed, 124 insertions(+), 58 deletions(-) diff --git a/src/bounties/BountyDescription.tsx b/src/bounties/BountyDescription.tsx index b9516e02..4980860a 100644 --- a/src/bounties/BountyDescription.tsx +++ b/src/bounties/BountyDescription.tsx @@ -19,27 +19,35 @@ interface codingLangProps { interface bounty_description_props { isPaid?: any; color?: any; + isBountyLandingPage?: boolean; } const BountyDescriptionContainer = styled.div` display: flex; flex-direction: column; height: 100%; - min-width: 519px; - max-width: 519px; + min-width: ${(props: any) => (props.isBountyLandingPage ? '270px' : '519px')}; + max-width: ${(props: any) => (props.isBountyLandingPage ? '270px' : '519px')}; padding-left: 17px; padding-right: 17px; `; -const Header = styled.div` +interface bounty_header_props { + isBountyLandingPage?: boolean; +} + +const Header = styled.div` display: flex; flex-direction: row; justify-content: space-between; height: 32px; margin-top: 16px; + margin-left: 0; + .NameContainer { display: flex; flex-direction: column; + width: ${(props: any) => (props.isBountyLandingPage ? '320px' : '')}; } `; @@ -75,11 +83,16 @@ const Description = styled.div` } `; -const LanguageContainer = styled.div` +interface LanguageContainerProps { + isBountyLandingPage?: boolean; +} + +const LanguageContainer = styled.div` display: flex; flex-wrap: wrap; width: 80%; margin-top: 10px; + margin-left: ${(p: any) => (p.isBountyLandingPage ? '95px' : '0px')}; `; const CodingLabels = styled.div` @@ -121,6 +134,8 @@ const BountyDescription = (props: BountiesDescriptionProps) => { const [replitLink, setReplitLink] = useState(''); const [descriptionImage, setDescriptionImage] = useState(''); + const { isBountyLandingPage } = props; + useEffect(() => { if (props.description) { const found = props?.description.match(/(https?:\/\/.*\.(?:png|jpg|jpeg|gif))(?![^`]*`)/); @@ -147,8 +162,11 @@ const BountyDescription = (props: BountiesDescriptionProps) => { return ( <> - -
+ +
{ {props.title?.slice(0, descriptionImage ? 80 : 120)} @@ -208,7 +227,7 @@ const BountyDescription = (props: BountiesDescriptionProps) => {
- + {replitLink && (
window.open(replitLink[0])} style={{ display: 'flex' }}> ` @@ -18,6 +19,7 @@ const PriceContainer = styled.div` align-items: flex-start; padding: 0px 24px; color: #909baa; + margin-left: ${(props: any) => (props.isBountyLandingPage ? '200px' : '0')}; padding-top: 41px; .PriceStaticTextContainer { width: 28px; @@ -101,6 +103,7 @@ const BountyPrice = (props: BountiesPriceProps) => { style={{ ...props.style }} + isBountyLandingPage={props.isBountyLandingPage} >
` min-width: 336px; max-width: 336px; display: flex; - padding: 40px 0px 0px 37px; + padding: ${(props: any) => + props.isBountyLandingPage ? '40px 0px 0px 20px' : '40px 0px 0px 37px'}; + margin-left: ${(props: any) => (props.isBountyLandingPage ? '-10px' : '0')}; `; const UserImage = styled.div` @@ -127,6 +133,7 @@ const BountyProfileView = (props: BountiesProfileProps) => { style={{ ...props?.UserProfileContainerStyle }} + isBountyLandingPage={props.isBountyLandingPage} > { + const featuredBounty = bountyStore.getFeaturedBounty(); + const [currentItems, setCurrentItems] = useState(1); + const [page, setPage] = useState(1); - &:hover { - background: ${colors.light.grayish.G950}; - } -`; + const widgetViewerProps = { + onPanelClick: (activeWorkspace?: string, bounty?: any) => { + if (bounty?.id) { + window.location.href = featuredBounty?.url || ''; + } + }, + checkboxIdToSelectedMap: {}, + checkboxIdToSelectedMapLanguage: {}, + fromBountyPage: true, + selectedWidget: 'bounties', + isBountyLandingPage: true, + loading: false, + currentItems, + setCurrentItems: (items: number) => setCurrentItems(items), + page, + setPage: (newPage: number) => setPage(newPage), + languageString: '', -const BountyTitle = styled.h3` - font-size: 16px; - font-weight: 500; - color: ${colors.light.text1}; - margin: 0 0 8px 0; -`; + bounties: featuredBounty + ? [ + { + body: { + id: featuredBounty.bountyId + }, + person: { + wanteds: [] + } + } + ] + : [] + }; -const BountyMeta = styled.div` - display: flex; - align-items: center; - justify-content: space-between; - color: ${colors.light.text2}; - font-size: 14px; -`; - -export const FeaturedBounties: React.FC = observer(() => { - const featuredBounty = bountyStore.getFeaturedBounty(); return (

Featured Bounties

- {featuredBounty ? ( - (window.location.href = featuredBounty.url)}> - Bounty #{featuredBounty.bountyId} - - View Details - - - ) : ( -
- No featured bounties at the moment + +
+ {featuredBounty ? ( + + ) : ( +
+ No featured bounties at the moment +
+ )}
- )} +
); }); diff --git a/src/pages/BountiesLandingPage/index.tsx b/src/pages/BountiesLandingPage/index.tsx index 2205fabe..9d537c16 100644 --- a/src/pages/BountiesLandingPage/index.tsx +++ b/src/pages/BountiesLandingPage/index.tsx @@ -26,8 +26,8 @@ const BountiesLandingPage: React.FC = () => { `; const ContentWrapper = styled.div` - max-width: 1200px; - min-height: 500px; + max-width: 1500px; + min-height: 650px; margin: 30px auto; width: 100%; padding: 40px 20px 20px 30px; @@ -44,7 +44,7 @@ const BountiesLandingPage: React.FC = () => { &:after { content: ''; position: absolute; - left: 63%; + left: 68%; top: 0; bottom: 0; width: 1px; diff --git a/src/people/interfaces.ts b/src/people/interfaces.ts index b4721885..1c997713 100644 --- a/src/people/interfaces.ts +++ b/src/people/interfaces.ts @@ -82,6 +82,7 @@ export interface BountiesProps { img?: string; id?: number; activeWorkspace?: string; + isBountyLandingPage?: boolean; } export interface BadgesProps { @@ -127,6 +128,7 @@ export interface NameTagProps { org_name?: string; org_uuid?: string; uuid?: string; + isBountyLandingPage?: boolean; } export interface NoneSpaceProps { @@ -413,6 +415,7 @@ export interface WantedViews2Props extends WantedViewsProps { coding_languages?: any; fromBountyPage?: boolean; activeWorkspace?: string; + isBountyLandingPage?: boolean; } export interface AboutViewProps { diff --git a/src/people/utils/AssignedUnassignedBounties.tsx b/src/people/utils/AssignedUnassignedBounties.tsx index 96ce6055..890accef 100644 --- a/src/people/utils/AssignedUnassignedBounties.tsx +++ b/src/people/utils/AssignedUnassignedBounties.tsx @@ -20,6 +20,7 @@ interface containerProps { unassigned_border?: string; grayish_G200?: string; color?: any; + isBountyLandingPage?: boolean; } const BountyContainer = styled.div` @@ -70,7 +71,7 @@ const DescriptionPriceContainer = styled.div` `; const UnassignedPersonProfile = styled.div` - min-width: 336px; + min-width: ${(props: any) => (props.isBountyLandingPage ? '282px' : '336px')}; min-height: 160px; max-height: auto; background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='10' ry='10' stroke='%23B0B7BCFF' stroke-width='3' stroke-dasharray='4' stroke-dashoffset='0' stroke-linecap='butt'/%3e%3c/svg%3e"); @@ -127,7 +128,8 @@ const Bounties = (props: BountiesProps) => { widget, created, org_uuid, - activeWorkspace + activeWorkspace, + isBountyLandingPage } = props; const color = colors['light']; @@ -176,6 +178,7 @@ const Bounties = (props: BountiesProps) => { org_img={props.img} codingLanguage={codingLanguage} created={created} + isBountyLandingPage={isBountyLandingPage} />
@@ -199,6 +202,7 @@ const Bounties = (props: BountiesProps) => { height: '16px', background: color.statusAssigned }} + isBountyLandingPage={isBountyLandingPage} />
@@ -236,6 +240,7 @@ const Bounties = (props: BountiesProps) => { maxWidth: '245px', minWidth: '245px' }} + isBountyLandingPage={isBountyLandingPage} />
@@ -243,6 +248,7 @@ const Bounties = (props: BountiesProps) => {
diff --git a/src/people/utils/NameTag.tsx b/src/people/utils/NameTag.tsx index cef3c093..09ad43cf 100644 --- a/src/people/utils/NameTag.tsx +++ b/src/people/utils/NameTag.tsx @@ -57,6 +57,7 @@ const Date = styled.div` `; interface WrapProps { readonly isSelected: boolean; + isBountyLandingPage?: boolean; } const Wrap = styled.div` @@ -65,6 +66,7 @@ const Wrap = styled.div` cursor: ${(p: any) => !p.isSelected && 'pointer'}; width: fit-content; margin-bottom: 10px; + margin-left: ${(p: any) => (p.isBountyLandingPage ? '95px' : '0px')}; color: #8e969c; // &:hover { // color: ${(p: any) => !p.isSelected && '#618AFF'}; @@ -83,7 +85,8 @@ function NameTag(props: NameTagProps) { widget, iconSize, textSize, - isPaid + isPaid, + isBountyLandingPage } = props; const { ui, main } = useStores(); const color = colors['light']; @@ -153,7 +156,7 @@ function NameTag(props: NameTagProps) { } return ( - +
)} diff --git a/src/people/widgetViews/WidgetSwitchViewer.tsx b/src/people/widgetViews/WidgetSwitchViewer.tsx index 4f8922fe..3b4a9e00 100644 --- a/src/people/widgetViews/WidgetSwitchViewer.tsx +++ b/src/people/widgetViews/WidgetSwitchViewer.tsx @@ -85,6 +85,7 @@ function WidgetSwitchViewer(props: any) { page: propsPage, setPage, languageString, + isBountyLandingPage, activeWorkspace, uuid, orgQueryLimit, @@ -104,8 +105,8 @@ function WidgetSwitchViewer(props: any) { minHeight: 132 } : { - minWidth: '1100px', - maxWidth: '1100px', + minWidth: isBountyLandingPage ? '900px' : '1100px', + maxWidth: isBountyLandingPage ? '900px' : '1100px', marginBottom: 16, borderRadius: '10px', display: 'flex', @@ -298,6 +299,7 @@ function WidgetSwitchViewer(props: any) { }} person={person} showModal={showModal} + isBountyLandingPage={isBountyLandingPage} setDeletePayload={setDeletePayload} fromBountyPage={props.fromBountyPage} activeWorkspace={activeWorkspace}