pl-fe: basic support for circles
Signed-off-by: Nicole Mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -37,6 +37,7 @@ const messages = defineMessages({
|
|||||||
profileDirectory: { id: 'navigation_bar.profile_directory', defaultMessage: 'Profile directory' },
|
profileDirectory: { id: 'navigation_bar.profile_directory', defaultMessage: 'Profile directory' },
|
||||||
bookmarks: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
bookmarks: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||||
lists: { id: 'column.lists', defaultMessage: 'Lists' },
|
lists: { id: 'column.lists', defaultMessage: 'Lists' },
|
||||||
|
circles: { id: 'column.circles', defaultMessage: 'Circles' },
|
||||||
groups: { id: 'column.groups', defaultMessage: 'Groups' },
|
groups: { id: 'column.groups', defaultMessage: 'Groups' },
|
||||||
events: { id: 'column.events', defaultMessage: 'Events' },
|
events: { id: 'column.events', defaultMessage: 'Events' },
|
||||||
dashboard: { id: 'navigation.dashboard', defaultMessage: 'Dashboard' },
|
dashboard: { id: 'navigation.dashboard', defaultMessage: 'Dashboard' },
|
||||||
@ -283,6 +284,15 @@ const SidebarMenu: React.FC = React.memo((): JSX.Element | null => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{features.circles && (
|
||||||
|
<SidebarLink
|
||||||
|
to='/circles'
|
||||||
|
icon={require('@tabler/icons/outline/chart-circles.svg')}
|
||||||
|
text={intl.formatMessage(messages.circles)}
|
||||||
|
onClick={closeSidebar}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{features.events && (
|
{features.events && (
|
||||||
<SidebarLink
|
<SidebarLink
|
||||||
to='/events'
|
to='/events'
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const messages = defineMessages({
|
|||||||
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||||
bookmarks: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
bookmarks: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||||
lists: { id: 'column.lists', defaultMessage: 'Lists' },
|
lists: { id: 'column.lists', defaultMessage: 'Lists' },
|
||||||
|
circles: { id: 'column.circles', defaultMessage: 'Circles' },
|
||||||
events: { id: 'column.events', defaultMessage: 'Events' },
|
events: { id: 'column.events', defaultMessage: 'Events' },
|
||||||
profileDirectory: { id: 'navigation_bar.profile_directory', defaultMessage: 'Profile directory' },
|
profileDirectory: { id: 'navigation_bar.profile_directory', defaultMessage: 'Profile directory' },
|
||||||
followedTags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' },
|
followedTags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' },
|
||||||
@ -100,6 +101,14 @@ const SidebarNavigation = React.memo(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (features.circles) {
|
||||||
|
menu.push({
|
||||||
|
to: '/circles',
|
||||||
|
text: intl.formatMessage(messages.circles),
|
||||||
|
icon: require('@tabler/icons/outline/chart-circles.svg'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (features.events) {
|
if (features.events) {
|
||||||
menu.push({
|
menu.push({
|
||||||
to: '/events',
|
to: '/events',
|
||||||
|
|||||||
@ -0,0 +1,62 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import Button from 'pl-fe/components/ui/button';
|
||||||
|
import Form from 'pl-fe/components/ui/form';
|
||||||
|
import HStack from 'pl-fe/components/ui/hstack';
|
||||||
|
import Input from 'pl-fe/components/ui/input';
|
||||||
|
import { useCreateCircle } from 'pl-fe/queries/accounts/use-circles';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
label: { id: 'circles.new.title_placeholder', defaultMessage: 'New circle title' },
|
||||||
|
title: { id: 'circles.new.create', defaultMessage: 'Add circle' },
|
||||||
|
create: { id: 'circles.new.create_title', defaultMessage: 'Add circle' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const NewCircleForm: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const [title, setTitle] = useState('');
|
||||||
|
|
||||||
|
const { mutate: createCircle, isPending } = useCreateCircle();
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setTitle(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent<Element>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
createCircle(title);
|
||||||
|
};
|
||||||
|
|
||||||
|
const label = intl.formatMessage(messages.label);
|
||||||
|
const create = intl.formatMessage(messages.create);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
<HStack space={2} alignItems='center'>
|
||||||
|
<label className='grow'>
|
||||||
|
<span style={{ display: 'none' }}>{label}</span>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type='text'
|
||||||
|
value={title}
|
||||||
|
disabled={isPending}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder={label}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={isPending}
|
||||||
|
onClick={handleSubmit}
|
||||||
|
theme='primary'
|
||||||
|
>
|
||||||
|
{create}
|
||||||
|
</Button>
|
||||||
|
</HStack>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { NewCircleForm as default };
|
||||||
67
packages/pl-fe/src/features/circles/index.tsx
Normal file
67
packages/pl-fe/src/features/circles/index.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import List, { ListItem } from 'pl-fe/components/list';
|
||||||
|
import Card from 'pl-fe/components/ui/card';
|
||||||
|
import Column from 'pl-fe/components/ui/column';
|
||||||
|
import HStack from 'pl-fe/components/ui/hstack';
|
||||||
|
import Icon from 'pl-fe/components/ui/icon';
|
||||||
|
import Spinner from 'pl-fe/components/ui/spinner';
|
||||||
|
import Stack from 'pl-fe/components/ui/stack';
|
||||||
|
import { useCircles } from 'pl-fe/queries/accounts/use-circles';
|
||||||
|
|
||||||
|
import { getOrderedLists } from '../lists';
|
||||||
|
|
||||||
|
import NewCircleForm from './components/new-circle-form';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.circles', defaultMessage: 'Circles' },
|
||||||
|
subheading: { id: 'circles.subheading', defaultMessage: 'Your circles' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const Circles: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const { data: circles } = useCircles(getOrderedLists);
|
||||||
|
|
||||||
|
if (!circles) {
|
||||||
|
return (
|
||||||
|
<Column>
|
||||||
|
<Spinner />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyMessage = <FormattedMessage id='empty_column.circles' defaultMessage="You don't have any circles yet. When you create one, it will show up here." />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column label={intl.formatMessage(messages.heading)}>
|
||||||
|
<Stack space={4}>
|
||||||
|
<NewCircleForm />
|
||||||
|
|
||||||
|
{!Object.keys(circles).length ? (
|
||||||
|
<Card variant='rounded' size='lg'>
|
||||||
|
{emptyMessage}
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<List>
|
||||||
|
{circles.map((circle) => (
|
||||||
|
<ListItem
|
||||||
|
key={circle.id}
|
||||||
|
// to={`/circles/${circle.id}`}
|
||||||
|
label={
|
||||||
|
<HStack alignItems='center' space={2}>
|
||||||
|
<Icon src={require('@tabler/icons/outline/list.svg')} size={20} />
|
||||||
|
<span>{circle.title}</span>
|
||||||
|
</HStack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Circles as default };
|
||||||
@ -8,9 +8,10 @@ import { getOrderedLists } from 'pl-fe/features/lists';
|
|||||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||||
import { useCompose } from 'pl-fe/hooks/use-compose';
|
import { useCompose } from 'pl-fe/hooks/use-compose';
|
||||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||||
|
import { useCircles } from 'pl-fe/queries/accounts/use-circles';
|
||||||
import { useLists } from 'pl-fe/queries/accounts/use-lists';
|
import { useLists } from 'pl-fe/queries/accounts/use-lists';
|
||||||
|
|
||||||
import type { Features } from 'pl-api';
|
import type { Circle, Features } from 'pl-api';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||||
@ -27,6 +28,8 @@ const messages = defineMessages({
|
|||||||
local_long: { id: 'privacy.local.long', defaultMessage: 'Only visible on your instance' },
|
local_long: { id: 'privacy.local.long', defaultMessage: 'Only visible on your instance' },
|
||||||
list_short: { id: 'privacy.list.short', defaultMessage: 'List only' },
|
list_short: { id: 'privacy.list.short', defaultMessage: 'List only' },
|
||||||
list_long: { id: 'privacy.list.long', defaultMessage: 'Visible to members of a list' },
|
list_long: { id: 'privacy.list.long', defaultMessage: 'Visible to members of a list' },
|
||||||
|
circle_short: { id: 'privacy.circle.short', defaultMessage: 'Circle only' },
|
||||||
|
circle_long: { id: 'privacy.circle.long', defaultMessage: 'Visible to members of a circle' },
|
||||||
subscribers_short: { id: 'privacy.subscribers.short', defaultMessage: 'Subscribers-only' },
|
subscribers_short: { id: 'privacy.subscribers.short', defaultMessage: 'Subscribers-only' },
|
||||||
subscribers_long: { id: 'privacy.subscribers.long', defaultMessage: 'Post to users subscribing you only' },
|
subscribers_long: { id: 'privacy.subscribers.long', defaultMessage: 'Post to users subscribing you only' },
|
||||||
|
|
||||||
@ -42,7 +45,7 @@ interface Option {
|
|||||||
items?: Array<Omit<Option, 'items'>>;
|
items?: Array<Omit<Option, 'items'>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItems = (features: Features, lists: ReturnType<typeof getOrderedLists>, intl: IntlShape) => [
|
const getItems = (features: Features, lists: ReturnType<typeof getOrderedLists>, circles: Array<Circle>, intl: IntlShape) => [
|
||||||
{
|
{
|
||||||
icon: require('@tabler/icons/outline/world.svg'),
|
icon: require('@tabler/icons/outline/world.svg'),
|
||||||
value: 'public',
|
value: 'public',
|
||||||
@ -96,6 +99,17 @@ const getItems = (features: Features, lists: ReturnType<typeof getOrderedLists>,
|
|||||||
text: intl.formatMessage(messages.list_short),
|
text: intl.formatMessage(messages.list_short),
|
||||||
meta: intl.formatMessage(messages.list_long),
|
meta: intl.formatMessage(messages.list_long),
|
||||||
} as Option : undefined,
|
} as Option : undefined,
|
||||||
|
features.circles && Object.keys(circles).length ? {
|
||||||
|
icon: require('@tabler/icons/outline/chart-circles.svg'),
|
||||||
|
value: '',
|
||||||
|
items: Object.values(circles).map((circle) => ({
|
||||||
|
icon: require('@tabler/icons/outline/list.svg'),
|
||||||
|
value: `circle:${circle.id}`,
|
||||||
|
text: circle.title,
|
||||||
|
})),
|
||||||
|
text: intl.formatMessage(messages.circle_short),
|
||||||
|
meta: intl.formatMessage(messages.circle_long),
|
||||||
|
} as Option : undefined,
|
||||||
].filter((option): option is Option => !!option);
|
].filter((option): option is Option => !!option);
|
||||||
|
|
||||||
interface IPrivacyDropdown {
|
interface IPrivacyDropdown {
|
||||||
@ -111,6 +125,7 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
|
|||||||
|
|
||||||
const compose = useCompose(composeId);
|
const compose = useCompose(composeId);
|
||||||
const { data: lists = [] } = useLists(getOrderedLists);
|
const { data: lists = [] } = useLists(getOrderedLists);
|
||||||
|
const { data: circles = [] } = useCircles(getOrderedLists);
|
||||||
|
|
||||||
const value = compose.privacy;
|
const value = compose.privacy;
|
||||||
const unavailable = compose.id;
|
const unavailable = compose.id;
|
||||||
@ -118,7 +133,7 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({
|
|||||||
const onChange = (value: string) => value && dispatch(changeComposeVisibility(composeId,
|
const onChange = (value: string) => value && dispatch(changeComposeVisibility(composeId,
|
||||||
value));
|
value));
|
||||||
|
|
||||||
const options = useMemo(() => getItems(features, lists, intl), [features, lists]);
|
const options = useMemo(() => getItems(features, lists, circles, intl), [features, lists, circles]);
|
||||||
const items: Array<MenuItem> = options.map(item => ({
|
const items: Array<MenuItem> = options.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
action: item.value ? () => onChange(item.value) : undefined,
|
action: item.value ? () => onChange(item.value) : undefined,
|
||||||
|
|||||||
@ -15,11 +15,11 @@ import NewListForm from './components/new-list-form';
|
|||||||
import type { List as ListEntity } from 'pl-api';
|
import type { List as ListEntity } from 'pl-api';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.lists', defaultMessage: 'Lists' },
|
heading: { id: 'column.circles', defaultMessage: 'Lists' },
|
||||||
subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },
|
subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const getOrderedLists = (lists: Array<ListEntity>) => {
|
const getOrderedLists = (lists: Array<Pick<ListEntity, 'title'>>) => {
|
||||||
if (!lists) {
|
if (!lists) {
|
||||||
return lists;
|
return lists;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,6 +64,7 @@ import {
|
|||||||
ChatIndex,
|
ChatIndex,
|
||||||
ChatWidget,
|
ChatWidget,
|
||||||
Circle,
|
Circle,
|
||||||
|
Circles,
|
||||||
CommunityTimeline,
|
CommunityTimeline,
|
||||||
ComposeEvent,
|
ComposeEvent,
|
||||||
Conversations,
|
Conversations,
|
||||||
@ -239,6 +240,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = React.memo(({ chil
|
|||||||
|
|
||||||
{features.lists && <WrappedRoute path='/lists' layout={DefaultLayout} component={Lists} content={children} />}
|
{features.lists && <WrappedRoute path='/lists' layout={DefaultLayout} component={Lists} content={children} />}
|
||||||
{features.lists && <WrappedRoute path='/list/:id' layout={DefaultLayout} component={ListTimeline} content={children} />}
|
{features.lists && <WrappedRoute path='/list/:id' layout={DefaultLayout} component={ListTimeline} content={children} />}
|
||||||
|
{features.circles && <WrappedRoute path='/circles' layout={DefaultLayout} component={Circles} content={children} />}
|
||||||
{features.bookmarks && <WrappedRoute path='/bookmarks/all' layout={DefaultLayout} component={Bookmarks} content={children} />}
|
{features.bookmarks && <WrappedRoute path='/bookmarks/all' layout={DefaultLayout} component={Bookmarks} content={children} />}
|
||||||
{features.bookmarks && <WrappedRoute path='/bookmarks/:id' layout={DefaultLayout} component={Bookmarks} content={children} />}
|
{features.bookmarks && <WrappedRoute path='/bookmarks/:id' layout={DefaultLayout} component={Bookmarks} content={children} />}
|
||||||
<WrappedRoute path='/bookmarks' layout={DefaultLayout} component={BookmarkFolders} content={children} />
|
<WrappedRoute path='/bookmarks' layout={DefaultLayout} component={BookmarkFolders} content={children} />
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export const Bookmarks = lazy(() => import('pl-fe/features/bookmarks'));
|
|||||||
export const BubbleTimeline = lazy(() => import('pl-fe/features/bubble-timeline'));
|
export const BubbleTimeline = lazy(() => import('pl-fe/features/bubble-timeline'));
|
||||||
export const ChatIndex = lazy(() => import('pl-fe/features/chats'));
|
export const ChatIndex = lazy(() => import('pl-fe/features/chats'));
|
||||||
export const Circle = lazy(() => import('pl-fe/features/circle'));
|
export const Circle = lazy(() => import('pl-fe/features/circle'));
|
||||||
|
export const Circles = lazy(() => import('pl-fe/features/circles'));
|
||||||
export const CommunityTimeline = lazy(() => import('pl-fe/features/community-timeline'));
|
export const CommunityTimeline = lazy(() => import('pl-fe/features/community-timeline'));
|
||||||
export const ComposeEditor = lazy(() => import('pl-fe/features/compose/editor'));
|
export const ComposeEditor = lazy(() => import('pl-fe/features/compose/editor'));
|
||||||
export const ComposeEvent = lazy(() => import('pl-fe/features/compose-event'));
|
export const ComposeEvent = lazy(() => import('pl-fe/features/compose-event'));
|
||||||
|
|||||||
@ -314,6 +314,10 @@
|
|||||||
"chats.main.blankslate.title": "No messages yet",
|
"chats.main.blankslate.title": "No messages yet",
|
||||||
"chats.main.blankslate_with_chats.subtitle": "Select from one of your open chats or create a new message.",
|
"chats.main.blankslate_with_chats.subtitle": "Select from one of your open chats or create a new message.",
|
||||||
"chats.main.blankslate_with_chats.title": "Select a chat",
|
"chats.main.blankslate_with_chats.title": "Select a chat",
|
||||||
|
"circles.new.create": "Add circle",
|
||||||
|
"circles.new.create_title": "Add circle",
|
||||||
|
"circles.new.title_placeholder": "New circle title",
|
||||||
|
"circles.subheading": "Your circles",
|
||||||
"column.admin.announcements": "Announcements",
|
"column.admin.announcements": "Announcements",
|
||||||
"column.admin.awaiting_approval": "Awaiting Approval",
|
"column.admin.awaiting_approval": "Awaiting Approval",
|
||||||
"column.admin.create_announcement": "Create announcement",
|
"column.admin.create_announcement": "Create announcement",
|
||||||
@ -344,6 +348,7 @@
|
|||||||
"column.bubble": "Bubble timeline",
|
"column.bubble": "Bubble timeline",
|
||||||
"column.chats": "Chats",
|
"column.chats": "Chats",
|
||||||
"column.circle": "Interactions circle",
|
"column.circle": "Interactions circle",
|
||||||
|
"column.circles": "Lists",
|
||||||
"column.community": "Local timeline",
|
"column.community": "Local timeline",
|
||||||
"column.crypto_donate": "Donate cryptocurrency",
|
"column.crypto_donate": "Donate cryptocurrency",
|
||||||
"column.developers": "Developers",
|
"column.developers": "Developers",
|
||||||
@ -725,6 +730,7 @@
|
|||||||
"empty_column.bookmarks": "You don't have any bookmarks yet. When you add one, it will show up here.",
|
"empty_column.bookmarks": "You don't have any bookmarks yet. When you add one, it will show up here.",
|
||||||
"empty_column.bookmarks.folder": "You don't have any bookmarks in this folder yet. When you add one, it will show up here.",
|
"empty_column.bookmarks.folder": "You don't have any bookmarks in this folder yet. When you add one, it will show up here.",
|
||||||
"empty_column.bubble": "There is nothing here! Write something publicly to fill it up",
|
"empty_column.bubble": "There is nothing here! Write something publicly to fill it up",
|
||||||
|
"empty_column.circles": "You don't have any circles yet. When you create one, it will show up here.",
|
||||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||||
"empty_column.dislikes": "No one has disliked this post yet. When someone does, they will show up here.",
|
"empty_column.dislikes": "No one has disliked this post yet. When someone does, they will show up here.",
|
||||||
@ -1315,6 +1321,8 @@
|
|||||||
"preferences.options.privacy_public": "Public",
|
"preferences.options.privacy_public": "Public",
|
||||||
"preferences.options.privacy_unlisted": "Unlisted",
|
"preferences.options.privacy_unlisted": "Unlisted",
|
||||||
"privacy.change": "Adjust post privacy",
|
"privacy.change": "Adjust post privacy",
|
||||||
|
"privacy.circle.long": "Visible to members of a circle",
|
||||||
|
"privacy.circle.short": "Circle only",
|
||||||
"privacy.direct.long": "Post to mentioned users only",
|
"privacy.direct.long": "Post to mentioned users only",
|
||||||
"privacy.direct.short": "Direct",
|
"privacy.direct.short": "Direct",
|
||||||
"privacy.list.long": "Visible to members of a list",
|
"privacy.list.long": "Visible to members of a list",
|
||||||
|
|||||||
61
packages/pl-fe/src/queries/accounts/use-circles.ts
Normal file
61
packages/pl-fe/src/queries/accounts/use-circles.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { useClient } from 'pl-fe/hooks/use-client';
|
||||||
|
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||||
|
|
||||||
|
import { queryClient } from '../client';
|
||||||
|
|
||||||
|
import type { Circle } from 'pl-api';
|
||||||
|
|
||||||
|
const useCircles = <T>(
|
||||||
|
select?: ((data: Array<Circle>) => T),
|
||||||
|
) => {
|
||||||
|
const client = useClient();
|
||||||
|
const features = useFeatures();
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['circles'],
|
||||||
|
queryFn: () => client.circles.fetchCircles(),
|
||||||
|
enabled: features.circles,
|
||||||
|
select,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useCircle = (circleId?: string) => useCircles((data) => circleId ? data.find(circle => circle.id === circleId) : undefined);
|
||||||
|
|
||||||
|
const useCreateCircle = () => {
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: ['circles', 'create'],
|
||||||
|
mutationFn: (title: string) => client.circles.createCircle(title),
|
||||||
|
onSettled: () => queryClient.invalidateQueries({ queryKey: ['circles'] }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDeleteCircle = () => {
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: ['circles', 'delete'],
|
||||||
|
mutationFn: (circleId: string) => client.circles.deleteCircle(circleId),
|
||||||
|
onSuccess: (_, deletedCircleId) => {
|
||||||
|
queryClient.setQueryData<Array<Circle>>(
|
||||||
|
['circles'],
|
||||||
|
(prevData) => prevData?.filter(({ id }) => id !== deletedCircleId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useUpdateCircle = (circleId: string) => {
|
||||||
|
const client = useClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: ['circles', 'update', circleId],
|
||||||
|
mutationFn: (title: string) => client.circles.updateCircle(circleId, title),
|
||||||
|
onSettled: () => queryClient.invalidateQueries({ queryKey: ['circles'] }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useCircles, useCircle, useCreateCircle, useDeleteCircle, useUpdateCircle };
|
||||||
Reference in New Issue
Block a user