diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..f213547 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,11 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals", + "rules": { + "no-restricted-imports": [ + "error", + { + "patterns": ["@mui/*/*/*"] + } + ] + } } diff --git a/package.json b/package.json index 365cb9e..0f09f7c 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "build-storybook": "storybook build" }, "dependencies": { + "@bundlr-network/client": "^0.11.2", "@lens-protocol/client": "^1.0.1", "@lens-protocol/react-web": "^1.0.1", "@lens-protocol/wagmi": "^1.0.1", @@ -40,6 +41,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "sass": "^1.62.1", + "sharp": "^0.32.1", "styled-components": "^6.0.0-rc.1", "typescript": "5.0.4", "wagmi": "0.12.13", diff --git a/src/assets/scss/_themes-vars.module.scss b/src/assets/scss/_themes-vars.module.scss index a470b03..b404af6 100644 --- a/src/assets/scss/_themes-vars.module.scss +++ b/src/assets/scss/_themes-vars.module.scss @@ -1,16 +1,16 @@ // paper & background -$paper: #ffffff; +$paper: #fffffe; // primary $primaryLight: #eef2f6; -$primaryMain: #2196f3; +$primaryMain: #078080; $primaryDark: #1e88e5; $primary200: #90caf9; $primary800: #1565c0; // secondary $secondaryLight: #ede7f6; -$secondaryMain: #673ab7; +$secondaryMain: #f45d48; $secondaryDark: #5e35b1; $secondary200: #b39ddb; $secondary800: #4527a0; diff --git a/src/components/Account.tsx b/src/components/Account.tsx index 190304c..05716fc 100644 --- a/src/components/Account.tsx +++ b/src/components/Account.tsx @@ -6,24 +6,21 @@ import styled from 'styled-components'; // easier to just override per our need const StyledConnectButtonWrapper = styled.div` .rainbowkit-connect-btn button { - height: 100px; - font-size: 1em; - width: 100%; - color: black; - text-decoration: underline; + height: 30px; + min-width: max-content; + text-decoration: none; border: 0px; cursor: pointer; + margin-top: 3px; } `; export const Account = () => { - const wagmiAccount = useAccount(); - return (
- +
diff --git a/src/components/CauseAttestationList.tsx b/src/components/CauseAttestationList.tsx index d83777f..d6d96a3 100644 --- a/src/components/CauseAttestationList.tsx +++ b/src/components/CauseAttestationList.tsx @@ -74,7 +74,7 @@ export const CauseAttestationList = ({ })} -
+ {/*

community support

@@ -93,7 +93,7 @@ export const CauseAttestationList = ({ -
+
*/} ); }; diff --git a/src/components/CollectButtonWrapper.tsx b/src/components/CollectButtonWrapper.tsx index 01cbd25..6dd463b 100644 --- a/src/components/CollectButtonWrapper.tsx +++ b/src/components/CollectButtonWrapper.tsx @@ -1,79 +1,113 @@ import { - Amount, TokenAllowanceLimit, AnyPublication, Post, - UsePublicationArgs, useActiveProfile, useActiveWallet, useApproveModule, - useCollect, useEnabledModules, usePublication, useWalletLogin, useCurrencies, useWhoCollectedPublication, - PublicationId, - FeeCollectPolicy -} from "@lens-protocol/react-web"; + Amount, + TokenAllowanceLimit, + AnyPublication, + Post, + UsePublicationArgs, + useActiveProfile, + useActiveWallet, + useApproveModule, + useCollect, + useEnabledModules, + usePublication, + useWalletLogin, + useCurrencies, + useWhoCollectedPublication, + PublicationId, + FeeCollectPolicy, +} from '@lens-protocol/react-web'; // https://github.com/lens-protocol/lens-sdk/blob/main/examples/web-wagmi/src/publications/UseCollect.tsx -import { useState } from "react"; -import { Alert, Chip } from "@mui/material"; +import { useState } from 'react'; +import { Alert, Chip } from '@mui/material'; -export const CollectButtonWrapper = ({ publicationId, currencyAddress, children }: { publicationId: string, currencyAddress: string, children: React.ReactNode }) => { - const { data, loading } = useActiveProfile(); - const { data: wallet } = useActiveWallet(); - const { data: enabledModules } = useEnabledModules(); - const { execute: approve } = useApproveModule(); - const collector = data!; - const { data: currencies = [], error: currenciesError, loading: currenciesLoading } = useCurrencies(); - const { data: publicationResult } = usePublication({ publicationId } as UsePublicationArgs); - const publication = publicationResult as Post; +export const CollectButtonWrapper = ({ + publicationId, + currencyAddress, + children, +}: { + publicationId: string; + currencyAddress: string; + children: React.ReactNode; +}) => { + const { data, loading } = useActiveProfile(); + const { data: wallet } = useActiveWallet(); + const { data: enabledModules } = useEnabledModules(); + const { execute: approve } = useApproveModule(); + const collector = data!; + const { + data: currencies = [], + error: currenciesError, + loading: currenciesLoading, + } = useCurrencies(); + const { data: publicationResult } = usePublication({ + publicationId, + } as UsePublicationArgs); + const publication = publicationResult as Post; - // publication will not refresh on collect, handle that manually - const [isCollected, setIsCollected] = useState(publication?.hasCollectedByMe); - // TODO query if alraeady approved + // publication will not refresh on collect, handle that manually + const [isCollected, setIsCollected] = useState(publication?.hasCollectedByMe); + // TODO query if alraeady approved - // approve first (not necessary for sandbox env) - const { execute: collect, error: collectEror, isPending } = useCollect({ collector, publication: publication as AnyPublication }); - // TODO fix action + // approve first (not necessary for sandbox env) + const { + execute: collect, + error: collectEror, + isPending, + } = useCollect({ collector, publication: publication as AnyPublication }); + // TODO fix action + const collectPolicy = publication?.collectPolicy as FeeCollectPolicy; - const collectPolicy = publication?.collectPolicy as FeeCollectPolicy; - - return ( - !publication || !wallet?.address ? ( -
Loading...
- ) - : ( - <> - {collectEror && !isPending && - {collectEror?.message} - } -
Collect Price ${collectPolicy?.amount.toNumber()}
- { - isCollected ? : ( -
{ - let results = await collect(); - // could approve from the amount of policy while easier to approve in bulk at once - // @ts-ignore - if (collectEror?.name === 'InsufficientAllowanceError') { - const approvalResults = await approve({ - spender: enabledModules?.collectModules.find(m => m.moduleName === 'FeeCollectModule')!.contractAddress!, - amount: Amount.erc20(currencies!.find(c => c.address === currencyAddress)!, 0.5), - limit: TokenAllowanceLimit.EXACT, - - }); - if (approvalResults.isSuccess()) { - results = await collect(); - console.log('approvalResults', approvalResults) - } else { - console.log('error in approval', approvalResults) - } - - } - if (results) { - console.log('collect', results) - if (results.isSuccess()) { - setIsCollected(true) - } - - } - - }}>{children}
- ) - } - - ) - ) -} \ No newline at end of file + return !publication || !wallet?.address ? ( +
+ + Please log in your Lens Profile for more details... + +
+ ) : ( + <> + {collectEror && !isPending && ( + {collectEror?.message} + )} +
Collect Price ${collectPolicy?.amount.toNumber()}
+ {isCollected ? ( + + ) : ( +
{ + let results = await collect(); + // could approve from the amount of policy while easier to approve in bulk at once + // @ts-ignore + if (collectEror?.name === 'InsufficientAllowanceError') { + const approvalResults = await approve({ + spender: enabledModules?.collectModules.find( + (m) => m.moduleName === 'FeeCollectModule', + )!.contractAddress!, + amount: Amount.erc20( + currencies!.find((c) => c.address === currencyAddress)!, + 0.5, + ), + limit: TokenAllowanceLimit.EXACT, + }); + if (approvalResults.isSuccess()) { + results = await collect(); + console.log('approvalResults', approvalResults); + } else { + console.log('error in approval', approvalResults); + } + } + if (results) { + console.log('collect', results); + if (results.isSuccess()) { + setIsCollected(true); + } + } + }} + > + {children} +
+ )} + + ); +}; diff --git a/src/components/CommentComposer.tsx b/src/components/CommentComposer.tsx new file mode 100644 index 0000000..5b12c8f --- /dev/null +++ b/src/components/CommentComposer.tsx @@ -0,0 +1,70 @@ +import { + ContentFocus, + ProfileOwnedByMe, + useCreateComment, + PublicationId, + CollectPolicyType, +} from '@lens-protocol/react-web'; +import { TextField, Button, Grid, InputAdornment } from '@mui/material'; +import SendIcon from '@mui/icons-material/Send'; +import { upload } from '../libs/lens/upload'; +import { useState } from 'react'; + +export const CommentComposer = ({ + publisher, + publicationId, +}: { + publisher: ProfileOwnedByMe; + publicationId: PublicationId; +}) => { + const { + execute: comment, + error, + isPending, + } = useCreateComment({ publisher, upload }); + + const [commentContent, setCommentContent] = useState(''); + + const submit = async (content: string) => { + let result = await comment({ + publicationId, + content, + contentFocus: ContentFocus.TEXT, + locale: 'en', + collect: { + type: CollectPolicyType.NO_COLLECT, + }, + }); + + setCommentContent(''); + }; + + return ( + setCommentContent(e.target.value)} + sx={{ + display: 'flex', + minWidth: '400px', + maxWidth: '800px', + }} + InputProps={{ + endAdornment: ( + + + + ), + }} + > + ); +}; diff --git a/src/components/ConnectLens.tsx b/src/components/ConnectLens.tsx index 34fb68c..5a7763b 100644 --- a/src/components/ConnectLens.tsx +++ b/src/components/ConnectLens.tsx @@ -1,62 +1,61 @@ -import { Event, mapPublicationAsEvent } from '@/domain/event'; import { Button, Grid } from '@mui/material'; -import { EventCard } from './EventCard'; -import styled from 'styled-components'; -import { useActiveProfile, useCreateProfile, useWalletLogin } from '@lens-protocol/react-web'; +import { + useActiveProfile, + useCreateProfile, + useWalletLogin, +} from '@lens-protocol/react-web'; import { useAccount, useSigner } from 'wagmi'; import { generateHandle } from '@/libs/lens/utils'; -import componentStyleOverrides from '@/themes/compStyleOverride'; // TODO group by upcoming vs past events export const ConnectLens = () => { - const { address, isConnected } = useAccount(); - const { execute: create } = useCreateProfile(); - const { data: signer, isError, isLoading } = useSigner(); - const activeProfileResults = useActiveProfile(); - const { execute: login, error, isPending } = useWalletLogin(); - const profile = activeProfileResults?.data!; - - return ( -
- {address && profile?.handle ?
- Lens: {profile?.handle} -
: ( - - ) + const { address, isConnected } = useAccount(); + const { execute: create } = useCreateProfile(); + const { data: signer, isError, isLoading } = useSigner(); + const activeProfileResults = useActiveProfile(); + const { execute: login, error, isPending } = useWalletLogin(); + const profile = activeProfileResults?.data!; + return ( +
+ {address && profile?.handle ? ( +
Lens: {profile?.handle}
+ ) : ( +
- ); + }} + > + Connect Lens + + )} +
+ ); }; diff --git a/src/components/EnterpriseLayout.tsx b/src/components/EnterpriseLayout.tsx index dfd4571..4621909 100644 --- a/src/components/EnterpriseLayout.tsx +++ b/src/components/EnterpriseLayout.tsx @@ -1,5 +1,4 @@ -import { Header } from '@/components/Header'; -import { Inter } from 'next/font/google'; +import Container from '@mui/material/Container'; export const metadata = { title: 'Lantana', @@ -12,9 +11,8 @@ export default function EnterpriseLayout({ children: React.ReactNode; }) { return ( -
-
+ {children} -
+ ); } diff --git a/src/components/EventCard.tsx b/src/components/EventCard.tsx index d9151ac..e646559 100644 --- a/src/components/EventCard.tsx +++ b/src/components/EventCard.tsx @@ -1,32 +1,6 @@ -import * as React from 'react'; -import { styled } from '@mui/material/styles'; -import Card from '@mui/material/Card'; -import CardHeader from '@mui/material/CardHeader'; -import CardMedia from '@mui/material/CardMedia'; -import CardContent from '@mui/material/CardContent'; -import CardActions from '@mui/material/CardActions'; -import Collapse from '@mui/material/Collapse'; -import Avatar from '@mui/material/Avatar'; -import IconButton, { IconButtonProps } from '@mui/material/IconButton'; -import Typography from '@mui/material/Typography'; -import { red } from '@mui/material/colors'; -import FavoriteIcon from '@mui/icons-material/Favorite'; -import ShareIcon from '@mui/icons-material/Share'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import MoreVertIcon from '@mui/icons-material/MoreVert'; -import Image from 'next/image'; -import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; -import { format, compareAsc, parseISO } from 'date-fns'; -import { Cause, CauseInput } from '@/domain/cause'; -import RecommendIcon from '@mui/icons-material/Recommend'; -import VolunteerActivismIcon from '@mui/icons-material/VolunteerActivism'; -import BookmarkAddIcon from '@mui/icons-material/BookmarkAdd'; -import CommentIcon from '@mui/icons-material/Comment'; -import PaidIcon from '@mui/icons-material/Paid'; -import { useActiveProfile, useCollect } from '@lens-protocol/react-web'; -import { EventInput, Event } from '@/domain/event'; -import { AvatarGroup } from '@mui/material'; -import { User } from '@/domain/user'; +import { Card, CardHeader, CardMedia, CardContent, Grid } from '@mui/material'; +import { format } from 'date-fns'; +import { Event } from '@/domain/event'; import { withIpfsGateway } from '@/libs/lens/utils'; // decouple lens specific actions / api from presentation @@ -39,43 +13,54 @@ export const EventCard = ({ actions?: any; isThumbnailOnly?: boolean; }) => { - const { data } = useActiveProfile(); - const collector = data!; - - const imageUrl = withIpfsGateway(event.imageUrl || ''); + const imageUrl = withIpfsGateway(event.imageUrl); const displayedDate = format(new Date() || event.date, 'MM/dd/yyyy HH:mm'); return ( - - - {event.title}
- - } - subheader={displayedDate} - /> - {event.imageUrl && ( - - )} - - - {event.volunteers.map((volunteer: Partial, i: number) => { - return ( - + + + + + + {event.imageUrl && ( + - ); - })} - - {!isThumbnailOnly && event.descriptionShort} - {!isThumbnailOnly && actions} + )} + + + {/* + {event.volunteers.map((volunteer: Partial, i: number) => { + return ( + + ); + })} + */} + + {event.descriptionShort} + + {actions} +
); }; diff --git a/src/components/EventCardAction.tsx b/src/components/EventCardAction.tsx index 3913572..818a8aa 100644 --- a/src/components/EventCardAction.tsx +++ b/src/components/EventCardAction.tsx @@ -8,34 +8,41 @@ import VolunteerActivismIcon from '@mui/icons-material/VolunteerActivism'; import CommentIcon from '@mui/icons-material/Comment'; import TwitterIcon from '@mui/icons-material/Twitter'; import SyncAltIcon from '@mui/icons-material/SyncAlt'; -import { ProfileOwnedByMe, useActiveProfile, useCollect, useCreateMirror } from '@lens-protocol/react-web'; +import { + ProfileOwnedByMe, + useActiveProfile, + useCollect, + useCreateMirror, +} from '@lens-protocol/react-web'; import styled from 'styled-components'; - -const MirrorButton = styled(IconButton) <{ isMirroredByMe: boolean }>` -color: ${props => (props.isMirroredByMe ? `blue` : `#757575`)}; -` - - - -export const EventCardActions = ({ profile, publication, collectAction, mirrorAction, isMirroredByMe = false }: - { - profile: ProfileOwnedByMe | null | undefined, publication: any, - collectAction: () => void, mirrorAction: () => void, - isMirroredByMe?: boolean - }) => { - - +const MirrorButton = styled(IconButton)<{ isMirroredByMe: boolean }>` + color: ${(props) => (props.isMirroredByMe ? `blue` : `#757575`)}; +`; + +export const EventCardActions = ({ + profile, + publication, + collectAction, + mirrorAction, + isMirroredByMe = false, +}: { + profile: ProfileOwnedByMe | null | undefined; + publication?: any; + collectAction?: () => void; + mirrorAction?: () => void; + isMirroredByMe?: boolean; +}) => { // change the share link to respective cause return ( - + { - event.preventDefault() - collectAction(); + event.preventDefault(); + collectAction!(); }} aria-label="support" > @@ -44,8 +51,8 @@ export const EventCardActions = ({ profile, publication, collectAction, mirrorAc { - event.preventDefault() - mirrorAction(); + event.preventDefault(); + mirrorAction!(); }} aria-label="share-to-lenster" > @@ -55,7 +62,9 @@ export const EventCardActions = ({ profile, publication, collectAction, mirrorAc aria-label="share-to-twitter" target="_blank" href="https://twitter.com/intent/tweet?text=Check%20out%20this%20cause&url=https://lantana.social/cause&via=Lantana&hashtags=lantana,lens,web3" - > + > + + {/* @@ -70,44 +79,52 @@ export const EventCardActions = ({ profile, publication, collectAction, mirrorAc ); }; - // smart component to pick up profile while pure component to show psuedo actions in case of unconnected // hack around lens sdk types to grouo conditionals -export const EventCardActionsWithProfile = ({ publication }: { publication: any }) => { - +export const EventCardActionsWithProfile = ({ + publication, +}: { + publication: any; +}) => { const { data: activeProfile } = useActiveProfile(); - const { execute: collect } = useCollect({ collector: activeProfile as ProfileOwnedByMe, publication }); - - const { execute: createMirror, isPending: isMirrorPending } = useCreateMirror({ - publisher: activeProfile!, + const { execute: collect } = useCollect({ + collector: activeProfile as ProfileOwnedByMe, + publication, }); + const { execute: createMirror, isPending: isMirrorPending } = useCreateMirror( + { + publisher: activeProfile!, + }, + ); + const isMirroredByMe = + publication.isOptimisticMirroredByMe || publication.mirrors.length > 0; + console.log('isMirrorPending', isMirrorPending, isMirroredByMe); + + const collectAction = activeProfile + ? () => { + // collect(); + } + : _.noop; + + const mirrorAction = + activeProfile && !isMirrorPending && !isMirroredByMe + ? async () => { + await createMirror({ + publication: publication, + }); + } + : _.noop; - const isMirroredByMe = publication.isOptimisticMirroredByMe || publication.mirrors.length > 0; - console.log('isMirrorPending', isMirrorPending, isMirroredByMe) - - const collectAction = activeProfile ? () => { - // collect(); - } : _.noop; - - const mirrorAction = activeProfile && !isMirrorPending && !isMirroredByMe ? async () => { - - await createMirror({ - publication: publication, - }); - } : _.noop; - - - - - return ; - -} \ No newline at end of file + return ( + + ); +}; diff --git a/src/components/EventList.tsx b/src/components/EventList.tsx index f407ed1..6bdb5f7 100644 --- a/src/components/EventList.tsx +++ b/src/components/EventList.tsx @@ -1,27 +1,74 @@ import { Event, mapPublicationAsEvent } from '@/domain/event'; -import { Grid } from '@mui/material'; +import { + Grid, + ImageList, + ImageListItem, + ImageListItemBar, + IconButton, +} from '@mui/material'; import { EventCard } from './EventCard'; import styled from 'styled-components'; +import Image from 'next/image'; +import { withIpfsGateway } from '@/libs/lens/utils'; +import { format } from 'date-fns'; +import InfoIcon from '@mui/icons-material/Info'; -const EventListWrapper = styled.div` - a { - text-decoration: none; - } -`; +// const EventListWrapper = styled.div` +// a { +// text-decoration: none; +// } + +// `; // TODO group by upcoming vs past events export const EventList = ({ events }: { events: Event[] }) => { return ( - - - {events.map((event, i) => { - return ( - - - - ); - })} - - + // + // + // {events.map((event, i) => { + // return ( + // + // + // + // ); + // })} + // + // + + + {events.map((event) => ( + + {event.title} + + + + } + /> + + ))} + ); }; diff --git a/src/components/Feed.tsx b/src/components/Feed.tsx index 638f5e6..fd30a43 100644 --- a/src/components/Feed.tsx +++ b/src/components/Feed.tsx @@ -1,29 +1,14 @@ -import IconButton, { IconButtonProps } from '@mui/material/IconButton'; -import { useRouter } from 'next/router'; - -import { Inter } from 'next/font/google'; import Grid from '@mui/material/Grid'; -import { Avatar, Button, Link } from '@mui/material'; -import Typography from '@mui/material/Typography'; +import { Link } from '@mui/material'; import { - usePublications, - useFeed, useExplorePublications, - useSearchPublications, - useComments, PublicationTypes, - PublicationSortCriteria, -} from '@lens-protocol/react-web'; -import { createFilters } from '@/libs/lens/create-filters'; -import { - useActiveProfile, - useActiveWallet, - useWalletLogout, } from '@lens-protocol/react-web'; -import { CauseCard } from './CauseCard'; +import { useActiveProfile } from '@lens-protocol/react-web'; import { Event, mapPublicationAsEvent } from '@/domain/event'; import { EventCard } from './EventCard'; +import { EventCardActions } from './EventCardAction'; import { styled } from 'styled-components'; // we want to use feed of lens directly @@ -37,19 +22,36 @@ const FeedItemsWrapper = styled.div` } `; -export const FeedItems = ({ publications, linkFactory = (event: Event) => `/cause/${event.causeKey}` }: { publications: any[], linkFactory?: (event: Event) => string }) => { +export const FeedItems = ({ + publications, + linkFactory = (event: Event) => + `/cause/${event.causeKey}?id=${event.publicationId}`, +}: { + publications: any[]; + linkFactory?: (event: Event) => string; +}) => { + const { data } = useActiveProfile(); + const actions = EventCardActions({ profile: data }); + // filter out void content: 'Happy Volunteering' return ( - + {publications.map((publication, i) => { const event = mapPublicationAsEvent(publication); - return ( - - - - - - ); + if (event.title != 'Happy Volunteering!') + return ( + + + + + + ); })} diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..cc6551e --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import Container from '@mui/material/Container'; +import Image from 'next/image'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import Paper from '@mui/material/Paper'; + +export default function Footer() { + return ( + + + + + + Lantana ©2023. Follow us + + + + ); +} diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 50bffff..68c258c 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,60 +1,93 @@ -import { AppBar, Box, Toolbar, Typography, useMediaQuery } from '@mui/material'; +import { AppBar, Box, Toolbar, Typography, Button } from '@mui/material'; import { AccountDrawer } from './AccountDrawer'; import { Account } from './Account'; - import Grid from '@mui/material/Grid'; -import { ConnectButton } from '@rainbow-me/rainbowkit'; -import { styled } from 'styled-components'; import Image from 'next/image'; import LogoImage from '../../public/logo.png'; -import Link from 'next/link'; import { ConnectLens } from './ConnectLens'; -const StyledAppBar = styled(AppBar)` - color: black; - background-color: #fff; -`; export const Header = () => { return ( - - - - - Lantana + + + + Lantana + + Lantana + + + {/* + - Discover - - {/* Organize - */} - - Enterprise - {/* + + + + Dashboard */} - - -
- - - - Account - - - - - - - - - -
-
-
-
-
+ + + + + + + + + + + Profile + + + + + + + + + + + + ); }; diff --git a/src/components/PublicationComments.tsx b/src/components/PublicationComments.tsx new file mode 100644 index 0000000..6f48919 --- /dev/null +++ b/src/components/PublicationComments.tsx @@ -0,0 +1,65 @@ +import { PublicationId, useComments } from '@lens-protocol/react-web'; +import { + List, + ListItem, + Divider, + ListItemAvatar, + Avatar, + ListItemText, + Typography, +} from '@mui/material'; +import * as React from 'react'; + +type PublicationCommentsProps = { + publicationId: PublicationId; +}; + +export function PublicationComments({ + publicationId, +}: PublicationCommentsProps) { + const { data, loading } = useComments({ commentsOf: publicationId }); + + if (loading) { + return
Loading...
; + } + + if (data) { + return ( + <> + {data && ( + + {data.map((item: any, i) => ( +
+ + + + + + + {item.createdAt} + + {' -- ' + item.metadata.content} + + } + > + + +
+ ))} +
+ )} + + ); + } else return

No items

; +} diff --git a/src/components/ReportRecommendations.tsx b/src/components/ReportRecommendations.tsx index 6212b18..ad29ea7 100644 --- a/src/components/ReportRecommendations.tsx +++ b/src/components/ReportRecommendations.tsx @@ -3,6 +3,7 @@ import { Box } from '@mui/material'; import { useEffect, useState } from 'react'; import React from 'react'; import Alert from '@mui/material/Alert'; +import CircularProgress from '@mui/material/CircularProgress'; import CheckIcon from '@mui/icons-material/Check'; // TOOD props data @@ -18,30 +19,45 @@ export const ReportRecommendations = ({ }: { aiRecommendations: AiRecommendations; }) => { - // Not asking openAI to return HTML directly as its css is hard to customize, also not a good secure practice return (
- - } severity="success">AI Recommendations for CSR Reporting. Base on OpenAI GPT 4.0 + } severity="success"> + AI Recommendations for CSR Reporting. Base on OpenAI GPT 4.0 +

CSR

- {aiRecommendations.csr || 'Loading...'} + {aiRecommendations.csr || ( + + + {' Loading'} + + )}
- } severity="success">AI Recommendations by ESG standards. Base on OpenAI GPT 4.0 + } severity="success"> + AI Recommendations by ESG standards. Base on OpenAI GPT 4.0 +

GRI standard

- {aiRecommendations.gri || 'Loading...'} + {aiRecommendations.gri || ( + + + {' Loading'} + + )}

SASB standard

- {aiRecommendations.sasb || 'Loading...'} + {aiRecommendations.sasb || ( + + + {' Loading'} + + )}
- -
); }; diff --git a/src/components/SocialLayout.tsx b/src/components/SocialLayout.tsx index 94b5dfd..8cf7b0d 100644 --- a/src/components/SocialLayout.tsx +++ b/src/components/SocialLayout.tsx @@ -1,6 +1,3 @@ -import { Header } from '@/components/Header'; -import { Inter } from 'next/font/google'; - import Container from '@mui/material/Container'; export const metadata = { @@ -14,11 +11,8 @@ export default function SocialLayout({ children: React.ReactNode; }) { return ( -
-
- - {children} - -
+ + {children} + ); } diff --git a/src/libs/lens/upload.ts b/src/libs/lens/upload.ts new file mode 100644 index 0000000..703023c --- /dev/null +++ b/src/libs/lens/upload.ts @@ -0,0 +1,59 @@ +import { WebBundlr } from '@bundlr-network/client'; +import { providers, utils } from 'ethers'; +import { fetchSigner } from 'wagmi/actions'; + +const TOP_UP = '200000000000000000'; // 0.2 MATIC +const MIN_FUNDS = 0.05; + +async function getBundlr() { + const signer = (await fetchSigner()) ?? console.log('Cannot get signer'); + const provider = signer?.provider ?? console.log('Cannot get provider'); + + if (provider instanceof providers.JsonRpcProvider) { + await provider.send('wallet_switchEthereumChain', [ + { chainId: utils.hexValue(80001) }, + ]); + } + + const bundlr = new WebBundlr( + 'https://devnet.bundlr.network', + 'matic', + signer?.provider, + { + providerUrl: 'https://rpc-mumbai.maticvigil.com/', + }, + ); + + await bundlr.ready(); + + const balance = await bundlr.getBalance( + (await signer?.getAddress()) ?? 'Cannot get address', + ); + + if (bundlr.utils.unitConverter(balance).toNumber() < MIN_FUNDS) { + await bundlr.fund(TOP_UP); + } + + return bundlr; +} + +export async function upload(data: unknown): Promise { + const confirm = window.confirm( + `In this example we will now upload metadata file via the Bundlr Network. +Please make sure your wallet is connected to the Polygon Mumbai testnet. +You can get some Mumbai MATIC from the Mumbai Faucet: https://mumbaifaucet.com/`, + ); + + if (!confirm) { + throw new Error('User cancelled'); + } + + const bundlr = await getBundlr(); + + const serialized = JSON.stringify(data); + const tx = await bundlr.upload(serialized, { + tags: [{ name: 'Content-Type', value: 'application/json' }], + }); + + return `https://arweave.net/${tx.id}`; +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 9259bd7..ec0c1c6 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -5,19 +5,27 @@ import { AccountProvider } from '@/components/AccountProvider'; import { AppProps } from 'next/app'; // defaultTheme -import themes from '../themes'; +import theme from '../themes'; +import { ThemeProvider } from '@mui/material/styles'; import { CssBaseline } from '@mui/material'; +import Footer from '@/components/Footer'; +import Header from '@/components/Header'; interface PageProps {} const MyApp = ({ Component, pageProps }: AppProps) => { + const themes = theme({ mode: 'light' }); return ( - - {/* */} - - - - + <> + + + +
+ + + +