sforkowany z mirror/soapbox
rodzic
859d93b289
commit
c61dcddd81
|
@ -4,7 +4,7 @@ import api, { getLinks } from 'soapbox/api';
|
||||||
import { formatBytes } from 'soapbox/utils/media';
|
import { formatBytes } from 'soapbox/utils/media';
|
||||||
import resizeImage from 'soapbox/utils/resize-image';
|
import resizeImage from 'soapbox/utils/resize-image';
|
||||||
|
|
||||||
import { importFetchedAccounts, importFetchedStatus } from './importer';
|
import { importFetchedAccounts, importFetchedStatus, importFetchedStatuses } from './importer';
|
||||||
import { fetchMedia, uploadMedia } from './media';
|
import { fetchMedia, uploadMedia } from './media';
|
||||||
import { closeModal, openModal } from './modals';
|
import { closeModal, openModal } from './modals';
|
||||||
import snackbar from './snackbar';
|
import snackbar from './snackbar';
|
||||||
|
@ -76,6 +76,13 @@ const EVENT_COMPOSE_CANCEL = 'EVENT_COMPOSE_CANCEL';
|
||||||
|
|
||||||
const EVENT_FORM_SET = 'EVENT_FORM_SET';
|
const EVENT_FORM_SET = 'EVENT_FORM_SET';
|
||||||
|
|
||||||
|
const RECENT_EVENTS_FETCH_REQUEST = 'RECENT_EVENTS_FETCH_REQUEST';
|
||||||
|
const RECENT_EVENTS_FETCH_SUCCESS = 'RECENT_EVENTS_FETCH_SUCCESS';
|
||||||
|
const RECENT_EVENTS_FETCH_FAIL = 'RECENT_EVENTS_FETCH_FAIL';
|
||||||
|
const JOINED_EVENTS_FETCH_REQUEST = 'JOINED_EVENTS_FETCH_REQUEST';
|
||||||
|
const JOINED_EVENTS_FETCH_SUCCESS = 'JOINED_EVENTS_FETCH_SUCCESS';
|
||||||
|
const JOINED_EVENTS_FETCH_FAIL = 'JOINED_EVENTS_FETCH_FAIL';
|
||||||
|
|
||||||
const noOp = () => new Promise(f => f(undefined));
|
const noOp = () => new Promise(f => f(undefined));
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -579,6 +586,48 @@ const editEvent = (id: string) => (dispatch: AppDispatch, getState: () => RootSt
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchRecentEvents = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (getState().status_lists.get('recent_events')?.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: RECENT_EVENTS_FETCH_REQUEST });
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/timelines/public?only_events=true').then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch({
|
||||||
|
type: RECENT_EVENTS_FETCH_SUCCESS,
|
||||||
|
statuses: response.data,
|
||||||
|
next: next ? next.uri : null,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: RECENT_EVENTS_FETCH_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchJoinedEvents = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (getState().status_lists.get('joined_events')?.isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: JOINED_EVENTS_FETCH_REQUEST });
|
||||||
|
|
||||||
|
api(getState).get('/api/v1/pleroma/events/joined_events').then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch({
|
||||||
|
type: JOINED_EVENTS_FETCH_SUCCESS,
|
||||||
|
statuses: response.data,
|
||||||
|
next: next ? next.uri : null,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: JOINED_EVENTS_FETCH_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
LOCATION_SEARCH_REQUEST,
|
LOCATION_SEARCH_REQUEST,
|
||||||
LOCATION_SEARCH_SUCCESS,
|
LOCATION_SEARCH_SUCCESS,
|
||||||
|
@ -624,6 +673,12 @@ export {
|
||||||
EVENT_PARTICIPATION_REQUEST_REJECT_FAIL,
|
EVENT_PARTICIPATION_REQUEST_REJECT_FAIL,
|
||||||
EVENT_COMPOSE_CANCEL,
|
EVENT_COMPOSE_CANCEL,
|
||||||
EVENT_FORM_SET,
|
EVENT_FORM_SET,
|
||||||
|
RECENT_EVENTS_FETCH_REQUEST,
|
||||||
|
RECENT_EVENTS_FETCH_SUCCESS,
|
||||||
|
RECENT_EVENTS_FETCH_FAIL,
|
||||||
|
JOINED_EVENTS_FETCH_REQUEST,
|
||||||
|
JOINED_EVENTS_FETCH_SUCCESS,
|
||||||
|
JOINED_EVENTS_FETCH_FAIL,
|
||||||
locationSearch,
|
locationSearch,
|
||||||
changeEditEventName,
|
changeEditEventName,
|
||||||
changeEditEventDescription,
|
changeEditEventDescription,
|
||||||
|
@ -677,4 +732,6 @@ export {
|
||||||
fetchEventIcs,
|
fetchEventIcs,
|
||||||
cancelEventCompose,
|
cancelEventCompose,
|
||||||
editEvent,
|
editEvent,
|
||||||
|
fetchRecentEvents,
|
||||||
|
fetchJoinedEvents,
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,7 +35,7 @@ const EventPreview: React.FC<IEventPreview> = ({ status, className, hideAction }
|
||||||
const banner = status.media_attachments?.find(({ description }) => description === 'Banner');
|
const banner = status.media_attachments?.find(({ description }) => description === 'Banner');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames('rounded-lg bg-gray-100 dark:bg-primary-800 relative overflow-hidden', className)}>
|
<div className={classNames('w-full rounded-lg bg-gray-100 dark:bg-primary-800 relative overflow-hidden', className)}>
|
||||||
<div className='absolute top-28 right-3'>
|
<div className='absolute top-28 right-3'>
|
||||||
{!hideAction && (account.id === me ? (
|
{!hideAction && (account.id === me ? (
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -87,9 +87,14 @@ const CardTitle: React.FC<ICardTitle> = ({ title }): JSX.Element => (
|
||||||
<Text size='xl' weight='bold' tag='h1' data-testid='card-title' truncate>{title}</Text>
|
<Text size='xl' weight='bold' tag='h1' data-testid='card-title' truncate>{title}</Text>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
interface ICardBody {
|
||||||
|
/** Classnames for the <div> element. */
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
/** A card's body. */
|
/** A card's body. */
|
||||||
const CardBody: React.FC = ({ children }): JSX.Element => (
|
const CardBody: React.FC<ICardBody> = ({ className, children }): JSX.Element => (
|
||||||
<div data-testid='card-body'>{children}</div>
|
<div data-testid='card-body' className={className}>{children}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export { Card, CardHeader, CardTitle, CardBody };
|
export { Card, CardHeader, CardTitle, CardBody };
|
||||||
|
|
|
@ -68,7 +68,6 @@ const messages = defineMessages({
|
||||||
userUnendorsed: { id: 'account.unendorse.success', defaultMessage: 'You are no longer featuring @{acct}' },
|
userUnendorsed: { id: 'account.unendorse.success', defaultMessage: 'You are no longer featuring @{acct}' },
|
||||||
profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' },
|
profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' },
|
||||||
header: { id: 'account.header.alt', defaultMessage: 'Profile header' },
|
header: { id: 'account.header.alt', defaultMessage: 'Profile header' },
|
||||||
composeEvent: { od: 'navigation.compose_event', defaultMessage: 'Create new event' },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IHeader {
|
interface IHeader {
|
||||||
|
@ -214,10 +213,6 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||||
history.push('/search');
|
history.push('/search');
|
||||||
};
|
};
|
||||||
|
|
||||||
const onComposeEvent = () => {
|
|
||||||
dispatch(openModal('COMPOSE_EVENT'));
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAvatarClick = () => {
|
const onAvatarClick = () => {
|
||||||
const avatar = normalizeAttachment({
|
const avatar = normalizeAttachment({
|
||||||
type: 'image',
|
type: 'image',
|
||||||
|
@ -302,13 +297,6 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||||
to: '/blocks',
|
to: '/blocks',
|
||||||
icon: require('@tabler/icons/ban.svg'),
|
icon: require('@tabler/icons/ban.svg'),
|
||||||
});
|
});
|
||||||
if (features.events) {
|
|
||||||
menu.push({
|
|
||||||
text: intl.formatMessage(messages.composeEvent),
|
|
||||||
action: onComposeEvent,
|
|
||||||
icon: require('@tabler/icons/calendar.svg'),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
menu.push({
|
menu.push({
|
||||||
text: intl.formatMessage(messages.mention, { name: account.username }),
|
text: intl.formatMessage(messages.mention, { name: account.username }),
|
||||||
|
|
|
@ -342,7 +342,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
||||||
<StillImage
|
<StillImage
|
||||||
src={banner.url}
|
src={banner.url}
|
||||||
alt={intl.formatMessage(messages.bannerHeader)}
|
alt={intl.formatMessage(messages.bannerHeader)}
|
||||||
className='absolute inset-0 object-cover md:rounded-t-xl'
|
className='absolute inset-0 object-cover md:rounded-t-xl h-full'
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -175,7 +175,7 @@ const EventDiscussion: React.FC<IEventDiscussion> = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
{me && <div className='sm:p-2 pt-0 border-b border-solid border-gray-200 dark:border-gray-800'>
|
{me && <div className='p-2 pt-0 border-b border-solid border-gray-200 dark:border-gray-800'>
|
||||||
<ComposeForm id={`reply:${status.id}`} autoFocus={false} event={status.id} />
|
<ComposeForm id={`reply:${status.id}`} autoFocus={false} event={status.id} />
|
||||||
</div>}
|
</div>}
|
||||||
<div ref={node} className='thread p-0 sm:p-2 shadow-none'>
|
<div ref={node} className='thread p-0 sm:p-2 shadow-none'>
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import ReactSwipeableViews from 'react-swipeable-views';
|
||||||
|
|
||||||
|
import EventPreview from 'soapbox/components/event-preview';
|
||||||
|
import { Card, Icon } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
import { makeGetStatus } from 'soapbox/selectors';
|
||||||
|
|
||||||
|
import PlaceholderEventPreview from '../../placeholder/components/placeholder-event-preview';
|
||||||
|
|
||||||
|
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
|
|
||||||
|
const Event = ({ id }: { id: string }) => {
|
||||||
|
const getStatus = useCallback(makeGetStatus(), []);
|
||||||
|
const status = useAppSelector(state => getStatus(state, { id }));
|
||||||
|
|
||||||
|
if (!status) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
className='w-full px-1'
|
||||||
|
to={`/@${status.getIn(['account', 'acct'])}/events/${status.id}`}
|
||||||
|
>
|
||||||
|
<EventPreview status={status} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IEventCarousel {
|
||||||
|
statusIds: ImmutableOrderedSet<string>
|
||||||
|
isLoading?: boolean | null
|
||||||
|
emptyMessage: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventCarousel: React.FC<IEventCarousel> = ({ statusIds, isLoading, emptyMessage }) => {
|
||||||
|
const [index, setIndex] = useState(0);
|
||||||
|
|
||||||
|
const handleChangeIndex = (index: number) => {
|
||||||
|
setIndex(index % statusIds.size);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <PlaceholderEventPreview />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statusIds.size === 0) {
|
||||||
|
return (
|
||||||
|
<Card variant='rounded' size='lg'>
|
||||||
|
{emptyMessage}
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className='relative -mx-1'>
|
||||||
|
{index !== 0 && (
|
||||||
|
<div className='z-10 absolute left-3 top-1/2 -mt-4'>
|
||||||
|
<button
|
||||||
|
data-testid='prev-page'
|
||||||
|
onClick={() => handleChangeIndex(index - 1)}
|
||||||
|
className='bg-white/50 dark:bg-gray-900/50 backdrop-blur rounded-full h-8 w-8 flex items-center justify-center'
|
||||||
|
>
|
||||||
|
<Icon src={require('@tabler/icons/chevron-left.svg')} className='text-black dark:text-white h-6 w-6' />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ReactSwipeableViews animateHeight index={index} onChangeIndex={handleChangeIndex}>
|
||||||
|
{statusIds.map(statusId => <Event key={statusId} id={statusId} />)}
|
||||||
|
</ReactSwipeableViews>
|
||||||
|
{index !== statusIds.size - 1 && (
|
||||||
|
<div className='z-10 absolute right-3 top-1/2 -mt-4'>
|
||||||
|
<button
|
||||||
|
data-testid='next-page'
|
||||||
|
onClick={() => handleChangeIndex(index + 1)}
|
||||||
|
className='bg-white/50 dark:bg-gray-900/50 backdrop-blur rounded-full h-8 w-8 flex items-center justify-center'
|
||||||
|
>
|
||||||
|
<Icon src={require('@tabler/icons/chevron-right.svg')} className='text-black dark:text-white h-6 w-6' />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EventCarousel;
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { Column } from 'soapbox/components/ui';
|
import { fetchJoinedEvents, fetchRecentEvents } from 'soapbox/actions/events';
|
||||||
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
|
import { Button, CardBody, CardHeader, CardTitle, Column, HStack } from 'soapbox/components/ui';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
import EventCarousel from './components/event-carousel';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.events', defaultMessage: 'Events' },
|
title: { id: 'column.events', defaultMessage: 'Events' },
|
||||||
|
@ -10,8 +15,53 @@ const messages = defineMessages({
|
||||||
const Events = () => {
|
const Events = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const recentEvents = useAppSelector((state) => state.status_lists.get('recent_events')!.items);
|
||||||
|
const recentEventsLoading = useAppSelector((state) => state.status_lists.get('recent_events')!.isLoading);
|
||||||
|
const joinedEvents = useAppSelector((state) => state.status_lists.get('joined_events')!.items);
|
||||||
|
const joinedEventsLoading = useAppSelector((state) => state.status_lists.get('joined_events')!.isLoading);
|
||||||
|
|
||||||
|
const onComposeEvent = () => {
|
||||||
|
dispatch(openModal('COMPOSE_EVENT'));
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(fetchRecentEvents());
|
||||||
|
dispatch(fetchJoinedEvents());
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.title)} />
|
<Column label={intl.formatMessage(messages.title)}>
|
||||||
|
<HStack className='mb-4' space={2} justifyContent='between'>
|
||||||
|
<CardTitle title='Recent events' />
|
||||||
|
<Button
|
||||||
|
className='ml-auto'
|
||||||
|
theme='primary'
|
||||||
|
size='sm'
|
||||||
|
onClick={onComposeEvent}
|
||||||
|
>
|
||||||
|
Create event
|
||||||
|
</Button>
|
||||||
|
</HStack>
|
||||||
|
<CardBody className='mb-2'>
|
||||||
|
<EventCarousel
|
||||||
|
statusIds={recentEvents}
|
||||||
|
isLoading={recentEventsLoading}
|
||||||
|
emptyMessage={<FormattedMessage id='events.recent_events.empty' defaultMessage='There are no public events yet.' />}
|
||||||
|
/>
|
||||||
|
</CardBody>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle title='Joined events' />
|
||||||
|
</CardHeader>
|
||||||
|
<CardBody>
|
||||||
|
<EventCarousel
|
||||||
|
statusIds={joinedEvents}
|
||||||
|
isLoading={joinedEventsLoading}
|
||||||
|
emptyMessage={<FormattedMessage id='events.joined_events.empty' defaultMessage="You haven't joined any event yet." />}
|
||||||
|
/>
|
||||||
|
</CardBody>
|
||||||
|
</Column>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { Stack, Text } from 'soapbox/components/ui';
|
||||||
|
|
||||||
|
import { generateText, randomIntFromInterval } from '../utils';
|
||||||
|
|
||||||
|
const PlaceholderEventPreview = () => {
|
||||||
|
const eventNameLength = randomIntFromInterval(5, 25);
|
||||||
|
const nameLength = randomIntFromInterval(5, 15);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='w-full rounded-lg bg-gray-100 dark:bg-primary-800 relative overflow-hidden animate-pulse text-primary-50 dark:text-primary-800'>
|
||||||
|
<div className='bg-primary-200 dark:bg-gray-600 h-40'>
|
||||||
|
{/* <img className='h-full w-full object-cover' src={banner.url} alt={intl.formatMessage(messages.bannerHeader)} />} */}
|
||||||
|
</div>
|
||||||
|
<Stack className='p-2.5' space={2}>
|
||||||
|
<Text weight='semibold'>{generateText(eventNameLength)}</Text>
|
||||||
|
|
||||||
|
<div className='flex gap-y-1 gap-x-2 flex-wrap text-gray-700 dark:text-gray-600'>
|
||||||
|
<span>{generateText(nameLength)}</span>
|
||||||
|
<span>{generateText(nameLength)}</span>
|
||||||
|
<span>{generateText(nameLength)}</span>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlaceholderEventPreview;
|
|
@ -43,6 +43,9 @@ const LinkFooter: React.FC = (): JSX.Element => {
|
||||||
{features.profileDirectory && (
|
{features.profileDirectory && (
|
||||||
<FooterLink to='/directory'><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></FooterLink>
|
<FooterLink to='/directory'><FormattedMessage id='navigation_bar.profile_directory' defaultMessage='Profile directory' /></FooterLink>
|
||||||
)}
|
)}
|
||||||
|
{features.events && (
|
||||||
|
<FooterLink to='/events'><FormattedMessage id='navigation_bar.events' defaultMessage='Events' /></FooterLink>
|
||||||
|
)}
|
||||||
<FooterLink to='/blocks'><FormattedMessage id='navigation_bar.blocks' defaultMessage='Blocks' /></FooterLink>
|
<FooterLink to='/blocks'><FormattedMessage id='navigation_bar.blocks' defaultMessage='Blocks' /></FooterLink>
|
||||||
<FooterLink to='/mutes'><FormattedMessage id='navigation_bar.mutes' defaultMessage='Mutes' /></FooterLink>
|
<FooterLink to='/mutes'><FormattedMessage id='navigation_bar.mutes' defaultMessage='Mutes' /></FooterLink>
|
||||||
{features.filters && (
|
{features.filters && (
|
||||||
|
|
|
@ -12,6 +12,14 @@ import {
|
||||||
BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
||||||
BOOKMARKED_STATUSES_EXPAND_FAIL,
|
BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||||
} from '../actions/bookmarks';
|
} from '../actions/bookmarks';
|
||||||
|
import {
|
||||||
|
RECENT_EVENTS_FETCH_REQUEST,
|
||||||
|
RECENT_EVENTS_FETCH_SUCCESS,
|
||||||
|
RECENT_EVENTS_FETCH_FAIL,
|
||||||
|
JOINED_EVENTS_FETCH_REQUEST,
|
||||||
|
JOINED_EVENTS_FETCH_SUCCESS,
|
||||||
|
JOINED_EVENTS_FETCH_FAIL,
|
||||||
|
} from '../actions/events';
|
||||||
import {
|
import {
|
||||||
FAVOURITED_STATUSES_FETCH_REQUEST,
|
FAVOURITED_STATUSES_FETCH_REQUEST,
|
||||||
FAVOURITED_STATUSES_FETCH_SUCCESS,
|
FAVOURITED_STATUSES_FETCH_SUCCESS,
|
||||||
|
@ -68,6 +76,8 @@ const initialState: State = ImmutableMap({
|
||||||
bookmarks: StatusListRecord(),
|
bookmarks: StatusListRecord(),
|
||||||
pins: StatusListRecord(),
|
pins: StatusListRecord(),
|
||||||
scheduled_statuses: StatusListRecord(),
|
scheduled_statuses: StatusListRecord(),
|
||||||
|
recent_events: StatusListRecord(),
|
||||||
|
joined_events: StatusListRecord(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const getStatusId = (status: string | StatusEntity) => typeof status === 'string' ? status : status.id;
|
const getStatusId = (status: string | StatusEntity) => typeof status === 'string' ? status : status.id;
|
||||||
|
@ -168,6 +178,18 @@ export default function statusLists(state = initialState, action: AnyAction) {
|
||||||
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
case SCHEDULED_STATUS_CANCEL_REQUEST:
|
||||||
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
case SCHEDULED_STATUS_CANCEL_SUCCESS:
|
||||||
return removeOneFromList(state, 'scheduled_statuses', action.id || action.status.id);
|
return removeOneFromList(state, 'scheduled_statuses', action.id || action.status.id);
|
||||||
|
case RECENT_EVENTS_FETCH_REQUEST:
|
||||||
|
return setLoading(state, 'recent_events', true);
|
||||||
|
case RECENT_EVENTS_FETCH_FAIL:
|
||||||
|
return setLoading(state, 'recent_events', false);
|
||||||
|
case RECENT_EVENTS_FETCH_SUCCESS:
|
||||||
|
return normalizeList(state, 'recent_events', action.statuses, action.next);
|
||||||
|
case JOINED_EVENTS_FETCH_REQUEST:
|
||||||
|
return setLoading(state, 'joined_events', true);
|
||||||
|
case JOINED_EVENTS_FETCH_FAIL:
|
||||||
|
return setLoading(state, 'joined_events', false);
|
||||||
|
case JOINED_EVENTS_FETCH_SUCCESS:
|
||||||
|
return normalizeList(state, 'joined_events', action.statuses, action.next);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue