mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-13 18:50:29 +03:00
209 lines
7.9 KiB
TypeScript
209 lines
7.9 KiB
TypeScript
import React, { useCallback } from 'react';
|
|
import { Box, Button, color, Icon, IconButton, Icons, Scroll, Spinner, Text } from 'folds';
|
|
import { useAtomValue } from 'jotai';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useClientConfig } from '../../../hooks/useClientConfig';
|
|
import { RoomCard, CardGrid, CardName, CardBase } from '../../../components/room-card';
|
|
import { allRoomsAtom } from '../../../state/room-list/roomList';
|
|
import { RoomSummaryLoader } from '../../../components/RoomSummaryLoader';
|
|
import {
|
|
Page,
|
|
PageContent,
|
|
PageContentCenter,
|
|
PageHeader,
|
|
PageHero,
|
|
PageHeroSection,
|
|
} from '../../../components/page';
|
|
import { RoomTopicViewer } from '../../../components/room-topic-viewer';
|
|
import * as css from './style.css';
|
|
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
|
|
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
|
|
import { BackRouteHandler } from '../../../components/BackRouteHandler';
|
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
|
import { millify } from '../../../plugins/millify';
|
|
import { getExploreServerPath } from '../../pathUtils';
|
|
|
|
type ServerCardProps = {
|
|
serverName: string;
|
|
onExplore: () => unknown;
|
|
};
|
|
|
|
function ServerCard({ serverName, onExplore }: ServerCardProps) {
|
|
const mx = useMatrixClient();
|
|
|
|
const fetchPublicRooms = useCallback(
|
|
() => mx.publicRooms({ server: serverName }),
|
|
[mx, serverName]
|
|
);
|
|
|
|
const { data, isLoading, isError } = useQuery({
|
|
queryKey: [serverName, `publicRooms`],
|
|
queryFn: fetchPublicRooms,
|
|
});
|
|
const publicRoomCount = data?.total_room_count_estimate;
|
|
|
|
return (
|
|
<CardBase>
|
|
<CardName>{serverName}</CardName>
|
|
<Box gap="100" grow="Yes" style={isError ? { color: color.Critical.Main } : undefined}>
|
|
{isLoading ? (
|
|
<Spinner size="50" />
|
|
) : (
|
|
<>
|
|
<Icon size="50" src={isError ? Icons.Warning : Icons.Category} />
|
|
<Text size="T200">
|
|
{publicRoomCount === undefined
|
|
? 'Error loading rooms'
|
|
: `${millify(publicRoomCount)} Public Rooms`}
|
|
</Text>
|
|
</>
|
|
)}
|
|
</Box>
|
|
<Button onClick={onExplore} variant="Secondary" fill="Soft" size="300">
|
|
<Text size="B300" truncate>
|
|
Explore
|
|
</Text>
|
|
</Button>
|
|
</CardBase>
|
|
);
|
|
}
|
|
|
|
export function FeaturedRooms() {
|
|
const { featuredCommunities } = useClientConfig();
|
|
const { rooms, spaces, servers } = featuredCommunities ?? {};
|
|
const allRooms = useAtomValue(allRoomsAtom);
|
|
const screenSize = useScreenSizeContext();
|
|
const { navigateSpace, navigateRoom } = useRoomNavigate();
|
|
const navigate = useNavigate();
|
|
|
|
const exploreServer = useCallback(
|
|
async (server: string) => {
|
|
navigate(getExploreServerPath(server));
|
|
},
|
|
[navigate]
|
|
);
|
|
|
|
return (
|
|
<Page>
|
|
{screenSize === ScreenSize.Mobile && (
|
|
<PageHeader>
|
|
<Box shrink="No">
|
|
<BackRouteHandler>
|
|
{(onBack) => (
|
|
<IconButton onClick={onBack}>
|
|
<Icon src={Icons.ArrowLeft} />
|
|
</IconButton>
|
|
)}
|
|
</BackRouteHandler>
|
|
</Box>
|
|
</PageHeader>
|
|
)}
|
|
<Box grow="Yes">
|
|
<Scroll hideTrack visibility="Hover">
|
|
<PageContent>
|
|
<PageContentCenter>
|
|
<Box direction="Column" gap="200">
|
|
<PageHeroSection>
|
|
<PageHero
|
|
icon={<Icon size="600" src={Icons.Bulb} />}
|
|
title="Featured"
|
|
subTitle="Find and explore public communities featured by your client provider."
|
|
/>
|
|
</PageHeroSection>
|
|
<Box direction="Column" gap="700">
|
|
{servers && servers.length > 0 && (
|
|
<Box direction="Column" gap="400">
|
|
<Text size="H4">Featured Servers</Text>
|
|
<CardGrid>
|
|
{servers.map((serverName) => (
|
|
<ServerCard
|
|
serverName={serverName}
|
|
onExplore={() => exploreServer(serverName)}
|
|
/>
|
|
))}
|
|
</CardGrid>
|
|
</Box>
|
|
)}
|
|
{spaces && spaces.length > 0 && (
|
|
<Box direction="Column" gap="400">
|
|
<Text size="H4">Featured Spaces</Text>
|
|
<CardGrid>
|
|
{spaces.map((roomIdOrAlias) => (
|
|
<RoomSummaryLoader key={roomIdOrAlias} roomIdOrAlias={roomIdOrAlias}>
|
|
{(roomSummary) => (
|
|
<RoomCard
|
|
roomIdOrAlias={roomIdOrAlias}
|
|
allRooms={allRooms}
|
|
avatarUrl={roomSummary?.avatar_url}
|
|
name={roomSummary?.name}
|
|
topic={roomSummary?.topic}
|
|
memberCount={roomSummary?.num_joined_members}
|
|
onView={navigateSpace}
|
|
renderTopicViewer={(name, topic, requestClose) => (
|
|
<RoomTopicViewer
|
|
name={name}
|
|
topic={topic}
|
|
requestClose={requestClose}
|
|
/>
|
|
)}
|
|
/>
|
|
)}
|
|
</RoomSummaryLoader>
|
|
))}
|
|
</CardGrid>
|
|
</Box>
|
|
)}
|
|
{rooms && rooms.length > 0 && (
|
|
<Box direction="Column" gap="400">
|
|
<Text size="H4">Featured Rooms</Text>
|
|
<CardGrid>
|
|
{rooms.map((roomIdOrAlias) => (
|
|
<RoomSummaryLoader key={roomIdOrAlias} roomIdOrAlias={roomIdOrAlias}>
|
|
{(roomSummary) => (
|
|
<RoomCard
|
|
roomIdOrAlias={roomIdOrAlias}
|
|
allRooms={allRooms}
|
|
avatarUrl={roomSummary?.avatar_url}
|
|
name={roomSummary?.name}
|
|
topic={roomSummary?.topic}
|
|
memberCount={roomSummary?.num_joined_members}
|
|
onView={navigateRoom}
|
|
renderTopicViewer={(name, topic, requestClose) => (
|
|
<RoomTopicViewer
|
|
name={name}
|
|
topic={topic}
|
|
requestClose={requestClose}
|
|
/>
|
|
)}
|
|
/>
|
|
)}
|
|
</RoomSummaryLoader>
|
|
))}
|
|
</CardGrid>
|
|
</Box>
|
|
)}
|
|
{((spaces && spaces.length === 0 && rooms && rooms.length === 0) ||
|
|
(!spaces && !rooms)) && (
|
|
<Box
|
|
className={css.RoomsInfoCard}
|
|
direction="Column"
|
|
justifyContent="Center"
|
|
alignItems="Center"
|
|
gap="200"
|
|
>
|
|
<Icon size="400" src={Icons.Info} />
|
|
<Text size="T300" align="Center">
|
|
No rooms or spaces are featured.
|
|
</Text>
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
</PageContentCenter>
|
|
</PageContent>
|
|
</Scroll>
|
|
</Box>
|
|
</Page>
|
|
);
|
|
}
|