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

Feat/latest project nostr #1283

Draft
wants to merge 29 commits into
base: staging
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9129fbe
Latest projects
turizspace Dec 20, 2023
044ef4f
Components for Latest Projects
turizspace Dec 20, 2023
5bb479d
Update Latest projects routes
turizspace Dec 20, 2023
fd8327c
Merge branch 'geyserfund:staging' into staging
turizspace Jan 5, 2024
bbb7e06
Updates to projeccard
turizspace Jan 5, 2024
65f5aef
fixes Noteslist.tsx
turizspace Jan 5, 2024
dad1e9b
layout fixes
turizspace Jan 5, 2024
a9d2be3
filter fix
turizspace Jan 5, 2024
9654e4a
nord card layout
turizspace Jan 5, 2024
c900135
Merge branch 'geyserfund:staging' into staging
turizspace Jan 12, 2024
026a369
Update Latest.tsx
turizspace Jan 12, 2024
fae0834
Update NoteCard.tsx
turizspace Jan 12, 2024
5338345
Update Noteslist.tsx
turizspace Jan 12, 2024
d92f17b
Update and rename Latest.tsx to LatestNostrProjects.tsx
turizspace Jan 15, 2024
ce01cbb
Update and rename NoteCard.tsx to NostrProjectCard.tsx
turizspace Jan 15, 2024
ed743dd
Update and rename Noteslist.tsx to NostrProjectList.tsx
turizspace Jan 15, 2024
38e2ecf
Update NostrProjectList.tsx
turizspace Jan 15, 2024
927c7f6
Update LatestNostrProjects.tsx
turizspace Jan 15, 2024
2359d06
Update routes.tsx
turizspace Jan 15, 2024
5f3a65c
Merge branch 'geyserfund:staging' into staging
turizspace Jan 25, 2024
b412cfe
fix build test errors
turizspace Jan 25, 2024
984e2f3
fix build test errors
turizspace Jan 25, 2024
053f49d
fix build test errors
turizspace Jan 25, 2024
e9d1d45
Merge branch 'geyserfund:staging' into staging
turizspace Jan 25, 2024
7d026ab
Update LatestNostrProjects.tsx
turizspace Jan 25, 2024
31af325
Update NostrProjectCard.tsx
turizspace Jan 25, 2024
16f1345
Update NostrProjectList.tsx
turizspace Jan 25, 2024
f7942b5
Update StatusFilterBody.tsx
turizspace Jan 25, 2024
d9e1370
Merge pull request #1259 from turizspace/staging
sajald77 Jan 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/config/routes/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { NotAuthorized, NotFoundPage } from '../../pages/fallback'
import { PrivacyPolicy, TermsAndConditions } from '../../pages/legal'
import { ErrorBoundary } from './ErrorBoundary'
import { renderPrivateRoute } from './PrivateRoute'
import LatestNostrProjects from '../../pages/landing/projects/views/LatestNostrProjects'

const Grants = () => import('../../pages/grants')
const ProjectLaunch = () => import('../../pages/projectCreate')
Expand Down Expand Up @@ -400,6 +401,10 @@ export const platformRoutes: RouteObject[] = [
return { Component: LandingFeed }
},
},
{
path:'latest',
Component: LatestNostrProjects,
},
],
},
{
Expand Down
61 changes: 51 additions & 10 deletions src/pages/landing/filters/status/StatusFilterBody.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Button, StackProps, VStack } from '@chakra-ui/react'
import { Button, StackProps, VStack, Box } from '@chakra-ui/react'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import { AiOutlineFieldTime } from 'react-icons/ai'

import { Body1 } from '../../../../components/typography'
import { useFilterContext } from '../../../../context'
Expand Down Expand Up @@ -38,7 +40,13 @@ export const StatusFilterBody = ({
{ type: ProjectType.Reward },
{ status: ProjectStatus.Active },
{ status: ProjectStatus.Inactive },
]
{
linkTo: '/latest',
text: 'Latest Projects',
icon: AiOutlineFieldTime,
size: '1.5em',
},
];

return (
<VStack
Expand All @@ -49,27 +57,60 @@ export const StatusFilterBody = ({
{...rest}
>
{options.map((option, index) => {
if (option.linkTo) {
return (
<Box>
<Link key={index} to={option.linkTo}>
<Button
background={
filters.type === option.type && filters.status === option.status
? 'transparent'
: 'neutral.100'
}
color="neutral.800"
onClick={() => handleClick(option)}
w="100%"
display="flex"
justifyContent="start"
_hover={{
background:
filters.type !== option.type || filters.status !== option.status
? 'neutral.100'
: 'neutral.100',
}}
>
{option.icon && (
<option.icon size={option.size} />
)}
<Body1 ml="10px" mr="94px" color={filters.type === option.type && filters.status === option.status ? 'neutral.900' : 'neutral.700'}>
{t(option.text)}
</Body1>
</Button>
</Link>
</Box>
);
}
const isActive =
filters.type === option.type && filters.status === option.status
filters.type === option.type && filters.status === option.status;

const { icon: Icon, text, color } = getStatusTypeButtonContent(option)
const { icon: Icon, text } = getStatusTypeButtonContent(option);
return (
<Button
key={index}
background={isActive ? 'neutral.100' : 'neutral.0'}
background={isActive ? 'neutral.100' : 'transparent'}
color="neutral.800"
onClick={() => handleClick(option)}
w="100%"
display="flex"
justifyContent="start"
>
<Icon color={color} />
<Body1 ml="10px" color={'neutral.900'}>
<Icon />
<Body1 ml="10px" color={isActive ? 'neutral.900' : 'neutral.700'}>
{t(text)}
</Body1>
</Button>
)
);
})}
</VStack>
)
}
);
};
93 changes: 93 additions & 0 deletions src/pages/landing/projects/components/NostrProjectCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import { Text, Box, Flex, Link as ChakraLink, useBreakpointValue } from '@chakra-ui/react';
import { ImageWithReload } from '../../../../components/ui/ImageWithReload';

interface RawContent {
display_name: string;
image: string;
about: string;
website: string;
}

interface NostrichType {
pubkey: string;
}

interface NostrProjectCardProps {
content: string;
nostrich: NostrichType;
}

const NostrProjectCard: React.FC<NostrProjectCardProps> = ({ content, nostrich }) => {
let parsedContent: RawContent;
try {
parsedContent = JSON.parse(content);
} catch (error) {
console.error('Error parsing JSON:', error);
parsedContent = { display_name: '', image: '', about: '', website: '' };
}
const { display_name, image, about, website } = parsedContent;

const imageSize = useBreakpointValue({ base: '120px', md: '120px' });

return (
<ChakraLink href={website} textDecoration="none" _hover={{ textDecoration: 'none' }}>
<Flex
display="flex"
alignItems="flex-start"
overflow="hidden"
margin="16px 0"
paddingTop="0px"
border="2px solid"
borderRadius="8px"
borderColor="neutral.200"
backgroundColor="neutral.0"
transition="border-color 0.5s"
boxShadow="none"
_hover={{ cursor: 'pointer', borderColor: 'neutral.200' }}
_active={{ borderColor: 'primary.300' }}
_focus={{ borderColor: 'primary.230' }}
>
<Box
flex="0 0 auto"
position="relative"
overflow="hidden"
height="120px"
width="120px"
marginRight={{ base: '0px', md: '20px' }}
max-height={imageSize}
>
<ImageWithReload src={image} />
</Box>

<Flex
flex="1"
flexDirection="column"
justifyContent="flex-start"
padding="8px"
>
<Text
fontFamily="Arial, sans-serif"
fontSize={{ base: '18px', md: '18px' }}
fontWeight="bold"
lineHeight="1.3"
marginBottom="10px"
noOfLines={{ base: 1, sm: 1, md: 1 }}
>
{display_name}
</Text>
<Text
fontSize={{ base: '14px', md: '14px' }}
lineHeight="1.4"
color="neutral.600"
noOfLines={{ base: 1, sm: 2, md: 3 }}
>
{about}
</Text>
</Flex>
</Flex>
</ChakraLink>
);
};

export default NostrProjectCard;
48 changes: 48 additions & 0 deletions src/pages/landing/projects/components/NostrProjectList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useState } from 'react';
import { Event } from 'nostr-tools';
import { Button, Flex } from '@chakra-ui/react';
import NostrProjectCard from './NostrProjectCard';

interface Props {
projects: Event[];
}

export default function NostrProjectList({ projects }: Props) {
const initialDisplayCount = 12;
const itemsPerPage = 10;
const [displayCount, setDisplayCount] = useState(initialDisplayCount);

const loadMore = () => {
const nextDisplayCount = displayCount + itemsPerPage;
setDisplayCount(nextDisplayCount);
};

const initialProjects = projects.slice(0, initialDisplayCount);

const renderProjects =
displayCount > initialDisplayCount ? projects.slice(0, displayCount) : initialProjects;

const buttonStyle = {
border: '1px solid',
padding: '8px 16px',
borderColor: 'neutral.200',
borderRadius: '8px',
margin: '8px 0',
cursor: 'pointer',
};

return (
<Flex direction="column" margin="0 20px" padding="10px">
<Flex direction="column">
{renderProjects.map((nostr, index) => (
<NostrProjectCard key={index} nostrich={{ pubkey: nostr.pubkey }} content={nostr.content} />
))}
{projects.length > displayCount && (
<Button style={buttonStyle} onClick={loadMore}>
Load More
</Button>
)}
</Flex>
</Flex>
);
}
63 changes: 63 additions & 0 deletions src/pages/landing/projects/views/LatestNostrProjects.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useState } from 'react';
import { Container, VStack, HStack, useBreakpointValue, useDisclosure } from '@chakra-ui/react';
import { SimplePool, Event } from 'nostr-tools';
import NostrProjectList from '../components/NostrProjectList';
import { FilterDrawer } from '../../filters/mobile/FilterDrawer';
import { MobileTopBar } from '../../filters/mobile/MobileTopBar';

const GEYSER_RELAY_URL = [
'wss://relay.geyser.fund',
];

export const LatestNostrProjects = () => {
const [pool, setPool] = useState(new SimplePool());
const initialEvents: Event[] = [];
const [events, setEvents] = useState(initialEvents);

useEffect(() => {
const _pool = new SimplePool();
setPool(_pool);

return () => {
_pool.close(GEYSER_RELAY_URL);
};
}, []);

useEffect(() => {
if (!pool) return;

const sub = pool.sub(GEYSER_RELAY_URL, [
{
kinds: [0],
limit: 100,
},
]);

sub.on('event', (event: Event) => {
setEvents((events) => [...events, event]);
});

return () => {
sub.unsub();
};
}, [pool]);

const isMobile = useBreakpointValue({ base: true, sm: true, md: true, lg: false });

const { isOpen, onClose } = useDisclosure();

return (
<Container>
<VStack>
{isMobile && <MobileTopBar title="Latest Projects" />}
{isMobile && <FilterDrawer isOpen={isOpen} onClose={onClose} />}

<HStack>
<NostrProjectList projects={events} />
</HStack>
</VStack>
</Container>
);
};

export default LatestNostrProjects;
Loading