Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
4 changes: 4 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
::-webkit-scrollbar-thumb:hover:horizontal {
background: #555;
}

.w3a-parent-container #w3a-modal {
background-color: rgba(0,0,0,0.4);
}
</style>
</head>
<body>
Expand Down
Binary file added src/assets/xp_badge.ico
Binary file not shown.
2 changes: 1 addition & 1 deletion src/components/login-modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const LoginModal: React.FC<LoginModalProps> = ({ open, onClose }) => {

return (
<Modal
sx={{ overflow: 'scroll', display: open ? 'flex' : 'none', zIndex: session.address && !session.user && open ? 3147483647 : 10000 }}
sx={{ overflow: 'scroll', display: open ? 'flex' : 'none' }}
open={open}
onClose={onClose}
closeAfterTransition
Expand Down
3 changes: 3 additions & 0 deletions src/components/login-modal/profile-form-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { useCreateUserMutation, useUpdateUserMutation } from '@src/graphql/gener
import { resolveSrc } from '@src/utils/image.ts';
import { getIpfsUri } from '@src/utils/publication.ts';
import { useAuth } from '@src/hooks/use-auth.ts';
import { useAccountSession } from '@src/hooks/use-account-session.ts';

// ----------------------------------------------------------------------

Expand All @@ -51,6 +52,7 @@ export const ProfileFormView: React.FC<ProfileFormProps> = ({
const [createUser, { loading: createUserLoading, error: errorCreatingProfile }] = useCreateUserMutation();
const [updateUser, { loading: updateUserLoading, error: errorUpdatingProfile }] = useUpdateUserMutation();
const { session } = useAuth();
const { refreshUser } = useAccountSession();

const loading = createUserLoading || updateUserLoading || registrationLoading;
const PaperElement = loading ? NeonPaper : Box;
Expand Down Expand Up @@ -169,6 +171,7 @@ export const ProfileFormView: React.FC<ProfileFormProps> = ({

setRegistrationLoading(false);
notifySuccess(SUCCESS.PROFILE_CREATED_SUCCESSFULLY);
setTimeout(refreshUser, 100)
onSuccess();
} catch (error) {
console.error('Error during profile registration:', error);
Expand Down
10 changes: 4 additions & 6 deletions src/hooks/use-notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { supabase } from '@src/utils/supabase';
import { type NotificationColumnsProps, NotificationPayload } from '@src/hooks/types';
import { setNotifications } from '@src/redux/notifications';
import {RootState} from "@redux/store.ts"
import { useAuth } from '@src/hooks/use-auth.ts';

interface UseNotificationsReturn {
getNotifications: (id: string) => Promise<void>;
Expand All @@ -15,7 +16,7 @@ interface UseNotificationsReturn {
}

export function useNotifications(): UseNotificationsReturn {
// TODO implement the notification using the user address instead of the id
const { session } = useAuth();
const dispatch = useDispatch();
const notifications: NotificationColumnsProps[] = useSelector(
(state: RootState) => state.notifications.notifications
Expand All @@ -41,10 +42,7 @@ export function useNotifications(): UseNotificationsReturn {
if (error) {
console.error('Error marking notification as read:', error);
} else {
const updatedNotifications = notifications.map((notification) =>
notification.id === id ? { ...notification, read: true } : notification
);
dispatch(setNotifications(updatedNotifications));
await getNotifications(session.address);
}
}

Expand All @@ -62,7 +60,7 @@ export function useNotifications(): UseNotificationsReturn {
const { error } = await supabase
.from('notifications')
.update({ read: true })
.eq('receiver_id', sessionData?.profile?.id);
.eq('receiver_id', session?.address);

if (error) {
console.error('Error marking all notifications as read:', error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { formatBalanceNumber } from '@src/utils/format-number.ts';

// ----------------------------------------------------------------------

export default function HeaderBalance() {
export default function HeaderMmcBalance() {
const { balance } = useGetBalance();
const router = useRouter();

Expand Down
55 changes: 55 additions & 0 deletions src/layouts/_common/header-xp-balance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// MUI IMPORTS
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import Tooltip from '@mui/material/Tooltip';

// LOCAL IMPORTS
import xpBadgeIcon from '@src/assets/xp_badge.ico';
import { paths } from '@src/routes/paths.ts';
import { useRouter } from '@src/routes/hooks';
import { formatBalanceNumber } from '@src/utils/format-number.ts';
import { useAuth } from '@src/hooks/use-auth.ts';

// ----------------------------------------------------------------------

export default function HeaderXpBalance() {
const { session } = useAuth();
const router = useRouter();

const handleGoFinance = () => {
router.push(paths.dashboard.finance);
};

return (
<Button variant={'text'} sx={{ px: 1.5, py: 1, mr: -0.75 }} onClick={handleGoFinance}>
<Stack direction="row" alignItems="center" justifyContent="center">
<Box
sx={{
width: 20,
height: 20,
marginRight: 1,
padding: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Tooltip title="You can redeem XP for MMC!">
<img
src={xpBadgeIcon}
alt="Xp badge"
style={{ width: 230, height: 20, borderRadius: '0.65rem' }}
/>
</Tooltip>
</Box>
<Tooltip title="XP balance">
<Typography variant="subtitle2" sx={{ textAlign: 'left' }} noWrap>
{formatBalanceNumber(session?.user?.xpBalance ?? 0)}
</Typography>
</Tooltip>
</Stack>
</Button>
);
}
3 changes: 2 additions & 1 deletion src/layouts/_common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { default as Searchbar } from './searchbar';
export { default as HeaderShadow } from './header-shadow';
export { default as HeaderSimple } from './header-simple';
export { default as AccountPopover } from './account-popover/index.tsx';
export { default as HeaderBalance } from './header-balance.tsx';
export { default as HeaderMmcBalance } from './header-mmc-balance.tsx';
export { default as HeaderXpBalance } from './header-xp-balance.tsx';
export { default as NavToggleButton } from './nav-toggle-button';
export { default as NotificationsPopover } from './notifications-popover';
15 changes: 9 additions & 6 deletions src/layouts/_common/notifications-popover/notification-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import { paths } from '@src/routes/paths.ts';
import { NotificationCategories, NotificationItemProps} from '@src/hooks/types'
import { useNotifications } from '@src/hooks/use-notifications.ts';

export default function NotificationItem({ notification, onMarkAsRead }: NotificationItemProps) {
export default function NotificationItem({ notification: n, onMarkAsRead }: NotificationItemProps) {
const notification = n.notification ? n.notification : n;
const router = useRouter();
const { deleteNotification } = useNotifications();
const typeOfNotification = notification?.payload?.category;
Expand All @@ -27,7 +28,7 @@ export default function NotificationItem({ notification, onMarkAsRead }: Notific
'';

const handleItemClick = () => {
onMarkAsRead(notification.id);
onMarkAsRead(notification?.id);

// Verify if is LIKE / COMMENT
if (
Expand All @@ -42,16 +43,18 @@ export default function NotificationItem({ notification, onMarkAsRead }: Notific
typeOfNotification === NotificationCategories.FOLLOW ||
typeOfNotification === NotificationCategories.JOIN
) {
router.push(paths.dashboard.user.root(`${notification.payload.data.from.id}`));
router.push(paths.dashboard.user.root(`${notification?.payload?.data?.from?.id}`));
}
};

if (!notification.payload) return <></>;

const renderAvatar = (
<ListItemAvatar>
<AvatarProfile src={notification.payload.data.from.avatar} sx={{ bgcolor: 'background.neutral' }} />
<AvatarProfile src={notification?.payload?.data?.from?.avatar} sx={{ bgcolor: 'background.neutral' }} />
</ListItemAvatar>
);
const description: string | null = notification.payload.data.content.rawDescription;
const description: string | null = notification?.payload?.data?.content?.rawDescription;
const renderText = (
<ListItemText
disableTypography
Expand All @@ -67,7 +70,7 @@ export default function NotificationItem({ notification, onMarkAsRead }: Notific
sx={{ typography: 'caption', color: 'text.disabled' }}
spacing={1}
>
<span>{formatDistanceToNow(new Date(notification.created_at), { addSuffix: true })}</span>
<span>{notification?.created_at ? formatDistanceToNow(new Date(notification.created_at), { addSuffix: true }) : ''}</span>
</Stack>
}
/>
Expand Down
5 changes: 3 additions & 2 deletions src/layouts/dashboard/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import SvgColor from '@src/components/svg-color';
import { useSettingsContext } from '@src/components/settings';
//
import { HEADER, NAV } from '../config-layout';
import { AccountPopover, HeaderBalance, NotificationsPopover } from '../_common';
import { AccountPopover, HeaderXpBalance, HeaderMmcBalance, NotificationsPopover } from '../_common';
import { PropsWithChildren } from 'react';

import { useDispatch, useSelector } from 'react-redux';
Expand Down Expand Up @@ -64,7 +64,8 @@ export default function Header({ children }: PropsWithChildren) {
>
{sessionData?.authenticated && (
<>
<HeaderBalance />
<HeaderXpBalance />
<HeaderMmcBalance />
<NotificationsPopover />
</>
)}
Expand Down
14 changes: 7 additions & 7 deletions src/libs/subscribe-notifications-supabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ export function subscribeToNotifications(
(payload) => {
handleEvents(payload, profileId, dispatch);
}
)
.on(
'postgres_changes',
{ event: 'UPDATE', schema: 'public', table, filter: `receiver_id=eq.${profileId}` },
(payload) => {
handleEvents(payload, profileId, dispatch);
}
);
// .on(
// 'postgres_changes',
// { event: 'UPDATE', schema: 'public', table, filter: `receiver_id=eq.${profileId}` },
// (payload) => {
// handleEvents(payload, profileId, dispatch);
// }
// );
});

channel.subscribe();
Expand Down
6 changes: 3 additions & 3 deletions src/sections/explore/components/explore-publications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { useResponsive } from '@src/hooks/use-responsive.ts';
import {useEffect} from "react"
import {setExploreLoading} from "@redux/loading"
import { useDispatch } from 'react-redux';
import { useGetAllPostsQuery } from '@src/graphql/generated/hooks.tsx';
import { useGetRecentPostsQuery } from '@src/graphql/generated/hooks.tsx';

// ----------------------------------------------------------------------

export const ExplorePublications = () => {
const dispatch = useDispatch();
const lgUp = useResponsive('up', 'lg');
const { data, loading } = useGetAllPostsQuery({ variables: { limit: 10 } })
const { data, loading } = useGetRecentPostsQuery({ variables: { limit: 100 } })

let minItemWidth = 250;
let maxItemWidth = 350;
Expand All @@ -26,7 +26,7 @@ export const ExplorePublications = () => {

return (
<CarouselPosterMini
data={data?.getAllPosts ?? []}
data={data?.getRecentPosts ?? []}
title="Publications"
minItemWidth={minItemWidth}
maxItemWidth={maxItemWidth}
Expand Down
32 changes: 22 additions & 10 deletions src/sections/explore/components/explore-top-publications.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
import CarouselTopTitles from "@src/components/carousel/variants/carousel-top-titles.tsx";
import { useEffect } from "react";
import { useEffect, useMemo } from 'react';
import { useDispatch } from "react-redux";
import { setExploreLoading } from "@redux/loading/index.ts";
import { useGetAllPostsQuery, useGetPopularPostsQuery } from '@src/graphql/generated/hooks.tsx';
import { useGetPopularPostsQuery, useGetRecentPostsQuery } from '@src/graphql/generated/hooks.tsx';
import { Post } from '@src/graphql/generated/graphql.ts';

// ----------------------------------------------------------------------

export const ExploreTopPublications = () => {
const dispatch = useDispatch();
const { data, loading } = useGetAllPostsQuery({ variables: { limit: 10 } })
const { data: explorePublications, loading: popularLoading } = useGetPopularPostsQuery({ variables: { limit: 10 } })
const { data: allData, loading: allLoading } = useGetRecentPostsQuery({ variables: { limit: 20 } });
const { data: popularData, loading: popularLoading } = useGetPopularPostsQuery({ variables: { limit: 10 } });

// Update loading state in Redux store
useEffect(() => {
dispatch(setExploreLoading({ key: "top", isLoading: loading || popularLoading }));
}, [loading, popularLoading]);
dispatch(setExploreLoading({ key: "top", isLoading: allLoading || popularLoading }));
}, [allLoading, popularLoading]);

const combinedPosts = [...(explorePublications?.getPopularPosts ?? []), ...(data?.getAllPosts ?? [])]
.filter((item, index, self) => self.findIndex((t) => t.id === item.id) === index)
.slice(0, 10);
const posts = useMemo(() => {
const popular = popularData?.getPopularPosts ?? [];
const recent = allData?.getRecentPosts ?? [];
const limit = 10;

return <CarouselTopTitles posts={combinedPosts} />;
if (popular.length >= limit) return popular.slice(0, limit);

const needed = limit - popular.length;
const fillers = recent
.filter((p: Post) => !popular.some((pp: Post) => pp.id === p.id))
.slice(0, needed);

return [...popular, ...fillers];
}, [popularData, allData]);

return <CarouselTopTitles posts={posts} />;
};
16 changes: 12 additions & 4 deletions src/sections/publication/views/publication-details-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default function PublicationDetailsView({ id }: Readonly<PublicationDetai
const { campaign, loading: campaignLoading, fetchSubscriptionCampaign } = useGetSubscriptionCampaign();
const { isActive: isCampaignActive, loading: isActiveLoading, fetchIsActive } = useGetCampaignIsActive();
const [loadPublications, { data: profilePublications, loading: profilePublicationsLoading }] = useGetPostsByAuthorLazyQuery();
const [initialized, setInitialized] = useState(false);

const isAccessFullyChecked = !accessLoading && !isAuthorizedLoading && !isActiveLoading && !campaignLoading;
const allLoaded = !publicationLoading && !isAuthLoading && !profilePublicationsLoading && isAccessFullyChecked;
Expand All @@ -59,26 +60,33 @@ export default function PublicationDetailsView({ id }: Readonly<PublicationDetai
const isPlayerVisible = hasAccess && session.authenticated && !accessLoading && !isAuthLoading;

useEffect(() => {
if (!ownerAddress || publicationLoading) return;
if (!ownerAddress || publicationLoading || profilePublications?.getPostsByAuthor) return;
fetchSubscriptionCampaign(ownerAddress);
loadPublications({variables: { author: ownerAddress, limit: 50 }});
}, [ownerAddress, publicationLoading]);
}, [ownerAddress, publicationLoading, profilePublications?.getPostsByAuthor]);

useEffect(() => {
if (!campaign || !session?.address) return;
fetchIsActive(campaign, session?.address);
}, [campaign, session?.address]);

useEffect(() => {
if (publication || !id) return;
loadPublication({variables: { getPostId: id }});
}, [id]);
}, [id, publication]);

useEffect(() => {
if (publication) {
dispatch(setPostCommentCount({ postId: publication.id, count: publication.commentCount }));
}
}, [publication]);

useEffect(() => {
if (allLoaded && !initialized) {
setInitialized(true);
}
}, [allLoaded, initialized]);

const handleSubscribe = () => {
if (!session.authenticated) {
dispatch(openLoginModal());
Expand All @@ -93,7 +101,7 @@ export default function PublicationDetailsView({ id }: Readonly<PublicationDetai

const filteredPublications = profilePublications?.getPostsByAuthor?.filter((publication: Post) => publication.id !== id) ?? [];

if (!allLoaded) return <LoadingScreen />;
if (!initialized || (initialized && !publication)) return <LoadingScreen />;
if (publication?.hidden || (!publication && !publicationLoading)) return <PublicationHidden />;

return (
Expand Down
2 changes: 2 additions & 0 deletions src/sections/user/CONSTANTS.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const emptyAddress = '0x0000000000000000000000000000000000000000'

export const TABS = [
{ value: 'publications', label: 'Publications' },
{ value: 'followers', label: 'Followers' },
Expand Down
3 changes: 2 additions & 1 deletion src/sections/user/components/profile-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { SponsoredAccessTrialButton } from '@src/components/sponsored-access-but
import { useAuth } from '@src/hooks/use-auth.ts';
import { ProfileHeaderProps } from '@src/sections/user/types.ts';
import LoadingButton from '@mui/lab/LoadingButton';
import { emptyAddress } from '@src/sections/user/CONSTANTS.tsx';

// ----------------------------------------------------------------------

Expand Down Expand Up @@ -64,7 +65,7 @@ const ProfileHeader = (props: PropsWithChildren<ProfileHeaderProps>) => {
}, [profile?.address]);

useEffect(() => {
if (!campaign || !session?.address) return;
if (!campaign || campaign === emptyAddress || !session?.address) return;
fetchIsActive(campaign, session?.address);
}, [campaign, session?.address]);

Expand Down
Loading
Loading