@ -0,0 +1 @@
|
|||||||
|
CHANGELOG.md merge=union
|
@ -0,0 +1,18 @@
|
|||||||
|
FROM node:18
|
||||||
|
|
||||||
|
RUN apt-get update &&\
|
||||||
|
apt-get install -y inotify-tools &&\
|
||||||
|
# clean up apt
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=development
|
||||||
|
|
||||||
|
COPY package.json .
|
||||||
|
COPY yarn.lock .
|
||||||
|
RUN yarn
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV DEVSERVER_URL=http://0.0.0.0:3036
|
||||||
|
CMD yarn dev
|
@ -1,6 +1,5 @@
|
|||||||
# Custom icons
|
# Custom icons
|
||||||
|
|
||||||
- fediverse.svg - Modified from Wikipedia, CC0
|
|
||||||
- verified.svg - Created by Alex Gleason. CC0
|
- verified.svg - Created by Alex Gleason. CC0
|
||||||
|
|
||||||
Fediverse logo: https://en.wikipedia.org/wiki/Fediverse#/media/File:Fediverse_logo_proposal.svg
|
Fediverse logo: https://en.wikipedia.org/wiki/Fediverse#/media/File:Fediverse_logo_proposal.svg
|
Before Width: | Height: | Size: 302 B After Width: | Height: | Size: 302 B |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 81 B After Width: | Height: | Size: 81 B |
Before Width: | Height: | Size: 812 B After Width: | Height: | Size: 812 B |
Before Width: | Height: | Size: 812 B After Width: | Height: | Size: 812 B |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 99 B After Width: | Height: | Size: 99 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 811 B |
Before Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 10 KiB |
@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"approval_required": false,
|
||||||
|
"avatar_upload_limit": 2000000,
|
||||||
|
"background_image": "https://fe.disroot.org/images/city.jpg",
|
||||||
|
"background_upload_limit": 4000000,
|
||||||
|
"banner_upload_limit": 4000000,
|
||||||
|
"description": "FEDIsroot - Federated social network powered by Pleroma (open beta)",
|
||||||
|
"description_limit": 5000,
|
||||||
|
"email": "admin@example.lan",
|
||||||
|
"languages": [
|
||||||
|
"en"
|
||||||
|
],
|
||||||
|
"max_toot_chars": 5000,
|
||||||
|
"pleroma": {
|
||||||
|
"metadata": {
|
||||||
|
"account_activation_required": false,
|
||||||
|
"features": [
|
||||||
|
"pleroma_api",
|
||||||
|
"akkoma_api",
|
||||||
|
"mastodon_api",
|
||||||
|
"mastodon_api_streaming",
|
||||||
|
"polls",
|
||||||
|
"v2_suggestions",
|
||||||
|
"pleroma_explicit_addressing",
|
||||||
|
"shareable_emoji_packs",
|
||||||
|
"multifetch",
|
||||||
|
"pleroma:api/v1/notifications:include_types_filter",
|
||||||
|
"editing",
|
||||||
|
"media_proxy",
|
||||||
|
"relay",
|
||||||
|
"pleroma_emoji_reactions",
|
||||||
|
"exposable_reactions",
|
||||||
|
"profile_directory",
|
||||||
|
"custom_emoji_reactions",
|
||||||
|
"pleroma:get:main/ostatus"
|
||||||
|
],
|
||||||
|
"federation": {
|
||||||
|
"enabled": true,
|
||||||
|
"exclusions": false,
|
||||||
|
"mrf_hashtag": {
|
||||||
|
"federated_timeline_removal": [],
|
||||||
|
"reject": [],
|
||||||
|
"sensitive": [
|
||||||
|
"nsfw"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mrf_object_age": {
|
||||||
|
"actions": [
|
||||||
|
"delist",
|
||||||
|
"strip_followers"
|
||||||
|
],
|
||||||
|
"threshold": 604800
|
||||||
|
},
|
||||||
|
"mrf_policies": [
|
||||||
|
"ObjectAgePolicy",
|
||||||
|
"TagPolicy",
|
||||||
|
"HashtagPolicy",
|
||||||
|
"InlineQuotePolicy"
|
||||||
|
],
|
||||||
|
"quarantined_instances": [],
|
||||||
|
"quarantined_instances_info": {
|
||||||
|
"quarantined_instances": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields_limits": {
|
||||||
|
"max_fields": 10,
|
||||||
|
"max_remote_fields": 20,
|
||||||
|
"name_length": 512,
|
||||||
|
"value_length": 2048
|
||||||
|
},
|
||||||
|
"post_formats": [
|
||||||
|
"text/plain",
|
||||||
|
"text/html",
|
||||||
|
"text/markdown",
|
||||||
|
"text/bbcode",
|
||||||
|
"text/x.misskeymarkdown"
|
||||||
|
],
|
||||||
|
"privileged_staff": false
|
||||||
|
},
|
||||||
|
"stats": {
|
||||||
|
"mau": 83
|
||||||
|
},
|
||||||
|
"vapid_public_key": null
|
||||||
|
},
|
||||||
|
"poll_limits": {
|
||||||
|
"max_expiration": 31536000,
|
||||||
|
"max_option_chars": 200,
|
||||||
|
"max_options": 20,
|
||||||
|
"min_expiration": 0
|
||||||
|
},
|
||||||
|
"registrations": false,
|
||||||
|
"stats": {
|
||||||
|
"domain_count": 6972,
|
||||||
|
"status_count": 8081,
|
||||||
|
"user_count": 357
|
||||||
|
},
|
||||||
|
"thumbnail": "https://fe.disroot.org/instance/thumbnail.jpeg",
|
||||||
|
"title": "FEDIsroot",
|
||||||
|
"upload_limit": 16000000,
|
||||||
|
"uri": "https://fe.disroot.org",
|
||||||
|
"urls": {
|
||||||
|
"streaming_api": "wss://fe.disroot.org"
|
||||||
|
},
|
||||||
|
"version": "2.7.2 (compatible; Akkoma 3.3.1-0-gaf90a4e51)"
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"account": {
|
||||||
|
"id": "ABDSjI3Q0R8aDaz1U0"
|
||||||
|
},
|
||||||
|
"content": "quoast",
|
||||||
|
"id": "AJsajx9hY4Q7IKQXEe",
|
||||||
|
"pleroma": {
|
||||||
|
"quote": {
|
||||||
|
"content": "<p>10</p>",
|
||||||
|
"id": "AJmoVikzI3SkyITyim"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,150 @@
|
|||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import { __stub } from 'soapbox/api';
|
||||||
|
import { mockStore, rootState } from 'soapbox/jest/test-helpers';
|
||||||
|
import { StatusListRecord } from 'soapbox/reducers/status-lists';
|
||||||
|
|
||||||
|
import { fetchStatusQuotes, expandStatusQuotes } from '../status-quotes';
|
||||||
|
|
||||||
|
const status = {
|
||||||
|
account: {
|
||||||
|
id: 'ABDSjI3Q0R8aDaz1U0',
|
||||||
|
},
|
||||||
|
content: 'quoast',
|
||||||
|
id: 'AJsajx9hY4Q7IKQXEe',
|
||||||
|
pleroma: {
|
||||||
|
quote: {
|
||||||
|
content: '<p>10</p>',
|
||||||
|
id: 'AJmoVikzI3SkyITyim',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusId = 'AJmoVikzI3SkyITyim';
|
||||||
|
|
||||||
|
describe('fetchStatusQuotes()', () => {
|
||||||
|
let store: ReturnType<typeof mockStore>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootState.set('me', '1234');
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const quotes = require('soapbox/__fixtures__/status-quotes.json');
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/pleroma/statuses/${statusId}/quotes`).reply(200, quotes, {
|
||||||
|
link: `<https://example.com/api/v1/pleroma/statuses/${statusId}/quotes?since_id=1>; rel='prev'`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch quotes from the API', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_REQUEST', statusId },
|
||||||
|
{ type: 'POLLS_IMPORT', polls: [] },
|
||||||
|
{ type: 'ACCOUNTS_IMPORT', accounts: [status.account] },
|
||||||
|
{ type: 'STATUSES_IMPORT', statuses: [status], expandSpoilers: false },
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_SUCCESS', statusId, statuses: [status], next: null },
|
||||||
|
];
|
||||||
|
await store.dispatch(fetchStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/pleroma/statuses/${statusId}/quotes`).networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch failed action', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_REQUEST', statusId },
|
||||||
|
{ type: 'STATUS_QUOTES_FETCH_FAIL', statusId, error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(fetchStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('expandStatusQuotes()', () => {
|
||||||
|
let store: ReturnType<typeof mockStore>;
|
||||||
|
|
||||||
|
describe('without a url', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootState
|
||||||
|
.set('me', '1234')
|
||||||
|
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: null }) }));
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should do nothing', async() => {
|
||||||
|
await store.dispatch(expandStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a url', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const state = rootState.set('me', '1234')
|
||||||
|
.set('status_lists', ImmutableMap({ [`quotes:${statusId}`]: StatusListRecord({ next: 'example' }) }));
|
||||||
|
store = mockStore(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a successful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const quotes = require('soapbox/__fixtures__/status-quotes.json');
|
||||||
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('example').reply(200, quotes, {
|
||||||
|
link: `<https://example.com/api/v1/pleroma/statuses/${statusId}/quotes?since_id=1>; rel='prev'`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fetch quotes from the API', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_REQUEST', statusId },
|
||||||
|
{ type: 'POLLS_IMPORT', polls: [] },
|
||||||
|
{ type: 'ACCOUNTS_IMPORT', accounts: [status.account] },
|
||||||
|
{ type: 'STATUSES_IMPORT', statuses: [status], expandSpoilers: false },
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_SUCCESS', statusId, statuses: [status], next: null },
|
||||||
|
];
|
||||||
|
await store.dispatch(expandStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an unsuccessful API request', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet('example').networkError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should dispatch failed action', async() => {
|
||||||
|
const expectedActions = [
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_REQUEST', statusId },
|
||||||
|
{ type: 'STATUS_QUOTES_EXPAND_FAIL', statusId, error: new Error('Network Error') },
|
||||||
|
];
|
||||||
|
await store.dispatch(expandStatusQuotes(statusId));
|
||||||
|
const actions = store.getActions();
|
||||||
|
|
||||||
|
expect(actions).toEqual(expectedActions);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
import type { DropdownPlacement } from 'soapbox/components/dropdown_menu';
|
import type { DropdownPlacement } from 'soapbox/components/dropdown-menu';
|
||||||
|
|
||||||
const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN';
|
const DROPDOWN_MENU_OPEN = 'DROPDOWN_MENU_OPEN';
|
||||||
const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE';
|
const DROPDOWN_MENU_CLOSE = 'DROPDOWN_MENU_CLOSE';
|
@ -0,0 +1,738 @@
|
|||||||
|
import { defineMessages, IntlShape } from 'react-intl';
|
||||||
|
|
||||||
|
import api, { getLinks } from 'soapbox/api';
|
||||||
|
import { formatBytes } from 'soapbox/utils/media';
|
||||||
|
import resizeImage from 'soapbox/utils/resize-image';
|
||||||
|
|
||||||
|
import { importFetchedAccounts, importFetchedStatus, importFetchedStatuses } from './importer';
|
||||||
|
import { fetchMedia, uploadMedia } from './media';
|
||||||
|
import { closeModal, openModal } from './modals';
|
||||||
|
import snackbar from './snackbar';
|
||||||
|
import {
|
||||||
|
STATUS_FETCH_SOURCE_FAIL,
|
||||||
|
STATUS_FETCH_SOURCE_REQUEST,
|
||||||
|
STATUS_FETCH_SOURCE_SUCCESS,
|
||||||
|
} from './statuses';
|
||||||
|
|
||||||
|
import type { AxiosError } from 'axios';
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
import type { APIEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||||
|
|
||||||
|
const LOCATION_SEARCH_REQUEST = 'LOCATION_SEARCH_REQUEST';
|
||||||
|
const LOCATION_SEARCH_SUCCESS = 'LOCATION_SEARCH_SUCCESS';
|
||||||
|
const LOCATION_SEARCH_FAIL = 'LOCATION_SEARCH_FAIL';
|
||||||
|
|
||||||
|
const EDIT_EVENT_NAME_CHANGE = 'EDIT_EVENT_NAME_CHANGE';
|
||||||
|
const EDIT_EVENT_DESCRIPTION_CHANGE = 'EDIT_EVENT_DESCRIPTION_CHANGE';
|
||||||
|
const EDIT_EVENT_START_TIME_CHANGE = 'EDIT_EVENT_START_TIME_CHANGE';
|
||||||
|
const EDIT_EVENT_HAS_END_TIME_CHANGE = 'EDIT_EVENT_HAS_END_TIME_CHANGE';
|
||||||
|
const EDIT_EVENT_END_TIME_CHANGE = 'EDIT_EVENT_END_TIME_CHANGE';
|
||||||
|
const EDIT_EVENT_APPROVAL_REQUIRED_CHANGE = 'EDIT_EVENT_APPROVAL_REQUIRED_CHANGE';
|
||||||
|
const EDIT_EVENT_LOCATION_CHANGE = 'EDIT_EVENT_LOCATION_CHANGE';
|
||||||
|
|
||||||
|
const EVENT_BANNER_UPLOAD_REQUEST = 'EVENT_BANNER_UPLOAD_REQUEST';
|
||||||
|
const EVENT_BANNER_UPLOAD_PROGRESS = 'EVENT_BANNER_UPLOAD_PROGRESS';
|
||||||
|
const EVENT_BANNER_UPLOAD_SUCCESS = 'EVENT_BANNER_UPLOAD_SUCCESS';
|
||||||
|
const EVENT_BANNER_UPLOAD_FAIL = 'EVENT_BANNER_UPLOAD_FAIL';
|
||||||
|
const EVENT_BANNER_UPLOAD_UNDO = 'EVENT_BANNER_UPLOAD_UNDO';
|
||||||
|
|
||||||
|
const EVENT_SUBMIT_REQUEST = 'EVENT_SUBMIT_REQUEST';
|
||||||
|
const EVENT_SUBMIT_SUCCESS = 'EVENT_SUBMIT_SUCCESS';
|
||||||
|
const EVENT_SUBMIT_FAIL = 'EVENT_SUBMIT_FAIL';
|
||||||
|
|
||||||
|
const EVENT_JOIN_REQUEST = 'EVENT_JOIN_REQUEST';
|
||||||
|
const EVENT_JOIN_SUCCESS = 'EVENT_JOIN_SUCCESS';
|
||||||
|
const EVENT_JOIN_FAIL = 'EVENT_JOIN_FAIL';
|
||||||
|
|
||||||
|
const EVENT_LEAVE_REQUEST = 'EVENT_LEAVE_REQUEST';
|
||||||
|
const EVENT_LEAVE_SUCCESS = 'EVENT_LEAVE_SUCCESS';
|
||||||
|
const EVENT_LEAVE_FAIL = 'EVENT_LEAVE_FAIL';
|
||||||
|
|
||||||
|
const EVENT_PARTICIPATIONS_FETCH_REQUEST = 'EVENT_PARTICIPATIONS_FETCH_REQUEST';
|
||||||
|
const EVENT_PARTICIPATIONS_FETCH_SUCCESS = 'EVENT_PARTICIPATIONS_FETCH_SUCCESS';
|
||||||
|
const EVENT_PARTICIPATIONS_FETCH_FAIL = 'EVENT_PARTICIPATIONS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const EVENT_PARTICIPATIONS_EXPAND_REQUEST = 'EVENT_PARTICIPATIONS_EXPAND_REQUEST';
|
||||||
|
const EVENT_PARTICIPATIONS_EXPAND_SUCCESS = 'EVENT_PARTICIPATIONS_EXPAND_SUCCESS';
|
||||||
|
const EVENT_PARTICIPATIONS_EXPAND_FAIL = 'EVENT_PARTICIPATIONS_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST = 'EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST';
|
||||||
|
const EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS = 'EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS';
|
||||||
|
const EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL = 'EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST = 'EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST';
|
||||||
|
const EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS = 'EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS';
|
||||||
|
const EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL = 'EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST = 'EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST';
|
||||||
|
const EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS = 'EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS';
|
||||||
|
const EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL = 'EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL';
|
||||||
|
|
||||||
|
const EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST = 'EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST';
|
||||||
|
const EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS = 'EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS';
|
||||||
|
const EVENT_PARTICIPATION_REQUEST_REJECT_FAIL = 'EVENT_PARTICIPATION_REQUEST_REJECT_FAIL';
|
||||||
|
|
||||||
|
const EVENT_COMPOSE_CANCEL = 'EVENT_COMPOSE_CANCEL';
|
||||||
|
|
||||||
|
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 messages = defineMessages({
|
||||||
|
exceededImageSizeLimit: { id: 'upload_error.image_size_limit', defaultMessage: 'Image exceeds the current file size limit ({limit})' },
|
||||||
|
success: { id: 'compose_event.submit_success', defaultMessage: 'Your event was created' },
|
||||||
|
editSuccess: { id: 'compose_event.edit_success', defaultMessage: 'Your event was edited' },
|
||||||
|
joinSuccess: { id: 'join_event.success', defaultMessage: 'Joined the event' },
|
||||||
|
joinRequestSuccess: { id: 'join_event.request_success', defaultMessage: 'Requested to join the event' },
|
||||||
|
view: { id: 'snackbar.view', defaultMessage: 'View' },
|
||||||
|
authorized: { id: 'compose_event.participation_requests.authorize_success', defaultMessage: 'User accepted' },
|
||||||
|
rejected: { id: 'compose_event.participation_requests.reject_success', defaultMessage: 'User rejected' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const locationSearch = (query: string, signal?: AbortSignal) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch({ type: LOCATION_SEARCH_REQUEST, query });
|
||||||
|
return api(getState).get('/api/v1/pleroma/search/location', { params: { q: query }, signal }).then(({ data: locations }) => {
|
||||||
|
dispatch({ type: LOCATION_SEARCH_SUCCESS, locations });
|
||||||
|
return locations;
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: LOCATION_SEARCH_FAIL });
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeEditEventName = (value: string) => ({
|
||||||
|
type: EDIT_EVENT_NAME_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeEditEventDescription = (value: string) => ({
|
||||||
|
type: EDIT_EVENT_DESCRIPTION_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeEditEventStartTime = (value: Date) => ({
|
||||||
|
type: EDIT_EVENT_START_TIME_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeEditEventEndTime = (value: Date) => ({
|
||||||
|
type: EDIT_EVENT_END_TIME_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeEditEventHasEndTime = (value: boolean) => ({
|
||||||
|
type: EDIT_EVENT_HAS_END_TIME_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeEditEventApprovalRequired = (value: boolean) => ({
|
||||||
|
type: EDIT_EVENT_APPROVAL_REQUIRED_CHANGE,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const changeEditEventLocation = (value: string | null) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
let location = null;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
location = getState().locations.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: EDIT_EVENT_LOCATION_CHANGE,
|
||||||
|
value: location,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadEventBanner = (file: File, intl: IntlShape) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const maxImageSize = getState().instance.configuration.getIn(['media_attachments', 'image_size_limit']) as number | undefined;
|
||||||
|
|
||||||
|
let progress = 0;
|
||||||
|
|
||||||
|
dispatch(uploadEventBannerRequest());
|
||||||
|
|
||||||
|
if (maxImageSize && (file.size > maxImageSize)) {
|
||||||
|
const limit = formatBytes(maxImageSize);
|
||||||
|
const message = intl.formatMessage(messages.exceededImageSizeLimit, { limit });
|
||||||
|
dispatch(snackbar.error(message));
|
||||||
|
dispatch(uploadEventBannerFail(true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeImage(file).then(file => {
|
||||||
|
const data = new FormData();
|
||||||
|
data.append('file', file);
|
||||||
|
// Account for disparity in size of original image and resized data
|
||||||
|
|
||||||
|
const onUploadProgress = ({ loaded }: any) => {
|
||||||
|
progress = loaded;
|
||||||
|
dispatch(uploadEventBannerProgress(progress));
|
||||||
|
};
|
||||||
|
|
||||||
|
return dispatch(uploadMedia(data, onUploadProgress))
|
||||||
|
.then(({ status, data }) => {
|
||||||
|
// If server-side processing of the media attachment has not completed yet,
|
||||||
|
// poll the server until it is, before showing the media attachment as uploaded
|
||||||
|
if (status === 200) {
|
||||||
|
dispatch(uploadEventBannerSuccess(data, file));
|
||||||
|
} else if (status === 202) {
|
||||||
|
const poll = () => {
|
||||||
|
dispatch(fetchMedia(data.id)).then(({ status, data }) => {
|
||||||
|
if (status === 200) {
|
||||||
|
dispatch(uploadEventBannerSuccess(data, file));
|
||||||
|
} else if (status === 206) {
|
||||||
|
setTimeout(() => poll(), 1000);
|
||||||
|
}
|
||||||
|
}).catch(error => dispatch(uploadEventBannerFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
poll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(error => dispatch(uploadEventBannerFail(error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadEventBannerRequest = () => ({
|
||||||
|
type: EVENT_BANNER_UPLOAD_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadEventBannerProgress = (loaded: number) => ({
|
||||||
|
type: EVENT_BANNER_UPLOAD_PROGRESS,
|
||||||
|
loaded,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadEventBannerSuccess = (media: APIEntity, file: File) => ({
|
||||||
|
type: EVENT_BANNER_UPLOAD_SUCCESS,
|
||||||
|
media,
|
||||||
|
file,
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadEventBannerFail = (error: AxiosError | true) => ({
|
||||||
|
type: EVENT_BANNER_UPLOAD_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const undoUploadEventBanner = () => ({
|
||||||
|
type: EVENT_BANNER_UPLOAD_UNDO,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitEvent = () =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const id = state.compose_event.id;
|
||||||
|
const name = state.compose_event.name;
|
||||||
|
const status = state.compose_event.status;
|
||||||
|
const banner = state.compose_event.banner;
|
||||||
|
const startTime = state.compose_event.start_time;
|
||||||
|
const endTime = state.compose_event.end_time;
|
||||||
|
const joinMode = state.compose_event.approval_required ? 'restricted' : 'free';
|
||||||
|
const location = state.compose_event.location;
|
||||||
|
|
||||||
|
if (!name || !name.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(submitEventRequest());
|
||||||
|
|
||||||
|
const params: Record<string, any> = {
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
start_time: startTime,
|
||||||
|
join_mode: joinMode,
|
||||||
|
content_type: 'text/markdown',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (endTime) params.end_time = endTime;
|
||||||
|
if (banner) params.banner_id = banner.id;
|
||||||
|
if (location) params.location_id = location.origin_id;
|
||||||
|
|
||||||
|
return api(getState).request({
|
||||||
|
url: id === null ? '/api/v1/pleroma/events' : `/api/v1/pleroma/events/${id}`,
|
||||||
|
method: id === null ? 'post' : 'put',
|
||||||
|
data: params,
|
||||||
|
}).then(({ data }) => {
|
||||||
|
dispatch(closeModal('COMPOSE_EVENT'));
|
||||||
|
dispatch(importFetchedStatus(data));
|
||||||
|
dispatch(submitEventSuccess(data));
|
||||||
|
dispatch(snackbar.success(id ? messages.editSuccess : messages.success, messages.view, `/@${data.account.acct}/events/${data.id}`));
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(submitEventFail(error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitEventRequest = () => ({
|
||||||
|
type: EVENT_SUBMIT_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitEventSuccess = (status: APIEntity) => ({
|
||||||
|
type: EVENT_SUBMIT_SUCCESS,
|
||||||
|
status,
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitEventFail = (error: AxiosError) => ({
|
||||||
|
type: EVENT_SUBMIT_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const joinEvent = (id: string, participationMessage?: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const status = getState().statuses.get(id);
|
||||||
|
|
||||||
|
if (!status || !status.event || status.event.join_state) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(joinEventRequest(status));
|
||||||
|
|
||||||
|
return api(getState).post(`/api/v1/pleroma/events/${id}/join`, {
|
||||||
|
participation_message: participationMessage,
|
||||||
|
}).then(({ data }) => {
|
||||||
|
dispatch(importFetchedStatus(data));
|
||||||
|
dispatch(joinEventSuccess(data));
|
||||||
|
dispatch(snackbar.success(
|
||||||
|
data.pleroma.event?.join_state === 'pending' ? messages.joinRequestSuccess : messages.joinSuccess,
|
||||||
|
messages.view,
|
||||||
|
`/@${data.account.acct}/events/${data.id}`,
|
||||||
|
));
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(joinEventFail(error, status, status?.event?.join_state || null));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const joinEventRequest = (status: StatusEntity) => ({
|
||||||
|
type: EVENT_JOIN_REQUEST,
|
||||||
|
id: status.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const joinEventSuccess = (status: APIEntity) => ({
|
||||||
|
type: EVENT_JOIN_SUCCESS,
|
||||||
|
id: status.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const joinEventFail = (error: AxiosError, status: StatusEntity, previousState: string | null) => ({
|
||||||
|
type: EVENT_JOIN_FAIL,
|
||||||
|
error,
|
||||||
|
id: status.id,
|
||||||
|
previousState,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leaveEvent = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const status = getState().statuses.get(id);
|
||||||
|
|
||||||
|
if (!status || !status.event || !status.event.join_state) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(leaveEventRequest(status));
|
||||||
|
|
||||||
|
return api(getState).post(`/api/v1/pleroma/events/${id}/leave`).then(({ data }) => {
|
||||||
|
dispatch(importFetchedStatus(data));
|
||||||
|
dispatch(leaveEventSuccess(data));
|
||||||
|
}).catch(function(error) {
|
||||||
|
dispatch(leaveEventFail(error, status));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const leaveEventRequest = (status: StatusEntity) => ({
|
||||||
|
type: EVENT_LEAVE_REQUEST,
|
||||||
|
id: status.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leaveEventSuccess = (status: APIEntity) => ({
|
||||||
|
type: EVENT_LEAVE_SUCCESS,
|
||||||
|
id: status.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const leaveEventFail = (error: AxiosError, status: StatusEntity) => ({
|
||||||
|
type: EVENT_LEAVE_FAIL,
|
||||||
|
id: status.id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventParticipations = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(fetchEventParticipationsRequest(id));
|
||||||
|
|
||||||
|
return api(getState).get(`/api/v1/pleroma/events/${id}/participations`).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedAccounts(response.data));
|
||||||
|
return dispatch(fetchEventParticipationsSuccess(id, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchEventParticipationsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEventParticipationsRequest = (id: string) => ({
|
||||||
|
type: EVENT_PARTICIPATIONS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventParticipationsSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: EVENT_PARTICIPATIONS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventParticipationsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: EVENT_PARTICIPATIONS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandEventParticipations = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const url = getState().user_lists.event_participations.get(id)?.next || null;
|
||||||
|
|
||||||
|
if (url === null) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandEventParticipationsRequest(id));
|
||||||
|
|
||||||
|
return api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedAccounts(response.data));
|
||||||
|
return dispatch(expandEventParticipationsSuccess(id, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandEventParticipationsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandEventParticipationsRequest = (id: string) => ({
|
||||||
|
type: EVENT_PARTICIPATIONS_EXPAND_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandEventParticipationsSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
||||||
|
type: EVENT_PARTICIPATIONS_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandEventParticipationsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: EVENT_PARTICIPATIONS_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventParticipationRequests = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(fetchEventParticipationRequestsRequest(id));
|
||||||
|
|
||||||
|
return api(getState).get(`/api/v1/pleroma/events/${id}/participation_requests`).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedAccounts(response.data.map(({ account }: APIEntity) => account)));
|
||||||
|
return dispatch(fetchEventParticipationRequestsSuccess(id, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(fetchEventParticipationRequestsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchEventParticipationRequestsRequest = (id: string) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventParticipationRequestsSuccess = (id: string, participations: APIEntity[], next: string | null) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS,
|
||||||
|
id,
|
||||||
|
participations,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventParticipationRequestsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandEventParticipationRequests = (id: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const url = getState().user_lists.event_participations.get(id)?.next || null;
|
||||||
|
|
||||||
|
if (url === null) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandEventParticipationRequestsRequest(id));
|
||||||
|
|
||||||
|
return api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedAccounts(response.data.map(({ account }: APIEntity) => account)));
|
||||||
|
return dispatch(expandEventParticipationRequestsSuccess(id, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandEventParticipationRequestsFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const expandEventParticipationRequestsRequest = (id: string) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandEventParticipationRequestsSuccess = (id: string, participations: APIEntity[], next: string | null) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
participations,
|
||||||
|
next,
|
||||||
|
});
|
||||||
|
|
||||||
|
const expandEventParticipationRequestsFail = (id: string, error: AxiosError) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const authorizeEventParticipationRequest = (id: string, accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(authorizeEventParticipationRequestRequest(id, accountId));
|
||||||
|
|
||||||
|
return api(getState)
|
||||||
|
.post(`/api/v1/pleroma/events/${id}/participation_requests/${accountId}/authorize`)
|
||||||
|
.then(() => {
|
||||||
|
dispatch(authorizeEventParticipationRequestSuccess(id, accountId));
|
||||||
|
dispatch(snackbar.success(messages.authorized));
|
||||||
|
})
|
||||||
|
.catch(error => dispatch(authorizeEventParticipationRequestFail(id, accountId, error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const authorizeEventParticipationRequestRequest = (id: string, accountId: string) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST,
|
||||||
|
id,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const authorizeEventParticipationRequestSuccess = (id: string, accountId: string) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS,
|
||||||
|
id,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const authorizeEventParticipationRequestFail = (id: string, accountId: string, error: AxiosError) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL,
|
||||||
|
id,
|
||||||
|
accountId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rejectEventParticipationRequest = (id: string, accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
dispatch(rejectEventParticipationRequestRequest(id, accountId));
|
||||||
|
|
||||||
|
return api(getState)
|
||||||
|
.post(`/api/v1/pleroma/events/${id}/participation_requests/${accountId}/reject`)
|
||||||
|
.then(() => {
|
||||||
|
dispatch(rejectEventParticipationRequestSuccess(id, accountId));
|
||||||
|
dispatch(snackbar.success(messages.rejected));
|
||||||
|
})
|
||||||
|
.catch(error => dispatch(rejectEventParticipationRequestFail(id, accountId, error)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const rejectEventParticipationRequestRequest = (id: string, accountId: string) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST,
|
||||||
|
id,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rejectEventParticipationRequestSuccess = (id: string, accountId: string) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS,
|
||||||
|
id,
|
||||||
|
accountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rejectEventParticipationRequestFail = (id: string, accountId: string, error: AxiosError) => ({
|
||||||
|
type: EVENT_PARTICIPATION_REQUEST_REJECT_FAIL,
|
||||||
|
id,
|
||||||
|
accountId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchEventIcs = (id: string) =>
|
||||||
|
(dispatch: any, getState: () => RootState) =>
|
||||||
|
api(getState).get(`/api/v1/pleroma/events/${id}/ics`);
|
||||||
|
|
||||||
|
const cancelEventCompose = () => ({
|
||||||
|
type: EVENT_COMPOSE_CANCEL,
|
||||||
|
});
|
||||||
|
|
||||||
|
const editEvent = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const status = getState().statuses.get(id)!;
|
||||||
|
|
||||||
|
dispatch({ type: STATUS_FETCH_SOURCE_REQUEST });
|
||||||
|
|
||||||
|
api(getState).get(`/api/v1/statuses/${id}/source`).then(response => {
|
||||||
|
dispatch({ type: STATUS_FETCH_SOURCE_SUCCESS });
|
||||||
|
dispatch({
|
||||||
|
type: EVENT_FORM_SET,
|
||||||
|
status,
|
||||||
|
text: response.data.text,
|
||||||
|
location: response.data.location,
|
||||||
|
});
|
||||||
|
dispatch(openModal('COMPOSE_EVENT'));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: STATUS_FETCH_SOURCE_FAIL, error });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
LOCATION_SEARCH_REQUEST,
|
||||||
|
LOCATION_SEARCH_SUCCESS,
|
||||||
|
LOCATION_SEARCH_FAIL,
|
||||||
|
EDIT_EVENT_NAME_CHANGE,
|
||||||
|
EDIT_EVENT_DESCRIPTION_CHANGE,
|
||||||
|
EDIT_EVENT_START_TIME_CHANGE,
|
||||||
|
EDIT_EVENT_END_TIME_CHANGE,
|
||||||
|
EDIT_EVENT_HAS_END_TIME_CHANGE,
|
||||||
|
EDIT_EVENT_APPROVAL_REQUIRED_CHANGE,
|
||||||
|
EDIT_EVENT_LOCATION_CHANGE,
|
||||||
|
EVENT_BANNER_UPLOAD_REQUEST,
|
||||||
|
EVENT_BANNER_UPLOAD_PROGRESS,
|
||||||
|
EVENT_BANNER_UPLOAD_SUCCESS,
|
||||||
|
EVENT_BANNER_UPLOAD_FAIL,
|
||||||
|
EVENT_BANNER_UPLOAD_UNDO,
|
||||||
|
EVENT_SUBMIT_REQUEST,
|
||||||
|
EVENT_SUBMIT_SUCCESS,
|
||||||
|
EVENT_SUBMIT_FAIL,
|
||||||
|
EVENT_JOIN_REQUEST,
|
||||||
|
EVENT_JOIN_SUCCESS,
|
||||||
|
EVENT_JOIN_FAIL,
|
||||||
|
EVENT_LEAVE_REQUEST,
|
||||||
|
EVENT_LEAVE_SUCCESS,
|
||||||
|
EVENT_LEAVE_FAIL,
|
||||||
|
EVENT_PARTICIPATIONS_FETCH_REQUEST,
|
||||||
|
EVENT_PARTICIPATIONS_FETCH_SUCCESS,
|
||||||
|
EVENT_PARTICIPATIONS_FETCH_FAIL,
|
||||||
|
EVENT_PARTICIPATIONS_EXPAND_REQUEST,
|
||||||
|
EVENT_PARTICIPATIONS_EXPAND_SUCCESS,
|
||||||
|
EVENT_PARTICIPATIONS_EXPAND_FAIL,
|
||||||
|
EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST,
|
||||||
|
EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS,
|
||||||
|
EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL,
|
||||||
|
EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST,
|
||||||
|
EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS,
|
||||||
|
EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL,
|
||||||
|
EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST,
|
||||||
|
EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS,
|
||||||
|
EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL,
|
||||||
|
EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST,
|
||||||
|
EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS,
|
||||||
|
EVENT_PARTICIPATION_REQUEST_REJECT_FAIL,
|
||||||
|
EVENT_COMPOSE_CANCEL,
|
||||||
|
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,
|
||||||
|
changeEditEventName,
|
||||||
|
changeEditEventDescription,
|
||||||
|
changeEditEventStartTime,
|
||||||
|
changeEditEventEndTime,
|
||||||
|
changeEditEventHasEndTime,
|
||||||
|
changeEditEventApprovalRequired,
|
||||||
|
changeEditEventLocation,
|
||||||
|
uploadEventBanner,
|
||||||
|
uploadEventBannerRequest,
|
||||||
|
uploadEventBannerProgress,
|
||||||
|
uploadEventBannerSuccess,
|
||||||
|
uploadEventBannerFail,
|
||||||
|
undoUploadEventBanner,
|
||||||
|
submitEvent,
|
||||||
|
submitEventRequest,
|
||||||
|
submitEventSuccess,
|
||||||
|
submitEventFail,
|
||||||
|
joinEvent,
|
||||||
|
joinEventRequest,
|
||||||
|
joinEventSuccess,
|
||||||
|
joinEventFail,
|
||||||
|
leaveEvent,
|
||||||
|
leaveEventRequest,
|
||||||
|
leaveEventSuccess,
|
||||||
|
leaveEventFail,
|
||||||
|
fetchEventParticipations,
|
||||||
|
fetchEventParticipationsRequest,
|
||||||
|
fetchEventParticipationsSuccess,
|
||||||
|
fetchEventParticipationsFail,
|
||||||
|
expandEventParticipations,
|
||||||
|
expandEventParticipationsRequest,
|
||||||
|
expandEventParticipationsSuccess,
|
||||||
|
expandEventParticipationsFail,
|
||||||
|
fetchEventParticipationRequests,
|
||||||
|
fetchEventParticipationRequestsRequest,
|
||||||
|
fetchEventParticipationRequestsSuccess,
|
||||||
|
fetchEventParticipationRequestsFail,
|
||||||
|
expandEventParticipationRequests,
|
||||||
|
expandEventParticipationRequestsRequest,
|
||||||
|
expandEventParticipationRequestsSuccess,
|
||||||
|
expandEventParticipationRequestsFail,
|
||||||
|
authorizeEventParticipationRequest,
|
||||||
|
authorizeEventParticipationRequestRequest,
|
||||||
|
authorizeEventParticipationRequestSuccess,
|
||||||
|
authorizeEventParticipationRequestFail,
|
||||||
|
rejectEventParticipationRequest,
|
||||||
|
rejectEventParticipationRequestRequest,
|
||||||
|
rejectEventParticipationRequestSuccess,
|
||||||
|
rejectEventParticipationRequestFail,
|
||||||
|
fetchEventIcs,
|
||||||
|
cancelEventCompose,
|
||||||
|
editEvent,
|
||||||
|
fetchRecentEvents,
|
||||||
|
fetchJoinedEvents,
|
||||||
|
};
|
@ -1,143 +0,0 @@
|
|||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api from '../api';
|
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
|
||||||
import type { History } from 'history';
|
|
||||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
|
||||||
import type { APIEntity } from 'soapbox/types/entities';
|
|
||||||
|
|
||||||
const GROUP_CREATE_REQUEST = 'GROUP_CREATE_REQUEST';
|
|
||||||
const GROUP_CREATE_SUCCESS = 'GROUP_CREATE_SUCCESS';
|
|
||||||
const GROUP_CREATE_FAIL = 'GROUP_CREATE_FAIL';
|
|
||||||
|
|
||||||
const GROUP_UPDATE_REQUEST = 'GROUP_UPDATE_REQUEST';
|
|
||||||
const GROUP_UPDATE_SUCCESS = 'GROUP_UPDATE_SUCCESS';
|
|
||||||
const GROUP_UPDATE_FAIL = 'GROUP_UPDATE_FAIL';
|
|
||||||
|
|
||||||
const GROUP_EDITOR_VALUE_CHANGE = 'GROUP_EDITOR_VALUE_CHANGE';
|
|
||||||
const GROUP_EDITOR_RESET = 'GROUP_EDITOR_RESET';
|
|
||||||
const GROUP_EDITOR_SETUP = 'GROUP_EDITOR_SETUP';
|
|
||||||
|
|
||||||
const submit = (routerHistory: History) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
const groupId = getState().group_editor.get('groupId') as string;
|
|
||||||
const title = getState().group_editor.get('title') as string;
|
|
||||||
const description = getState().group_editor.get('description') as string;
|
|
||||||
const coverImage = getState().group_editor.get('coverImage') as any;
|
|
||||||
|
|
||||||
if (groupId === null) {
|
|
||||||
dispatch(create(title, description, coverImage, routerHistory));
|
|
||||||
} else {
|
|
||||||
dispatch(update(groupId, title, description, coverImage, routerHistory));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const create = (title: string, description: string, coverImage: File, routerHistory: History) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(createRequest());
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('title', title);
|
|
||||||
formData.append('description', description);
|
|
||||||
|
|
||||||
if (coverImage !== null) {
|
|
||||||
formData.append('cover_image', coverImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
api(getState).post('/api/v1/groups', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
|
||||||
dispatch(createSuccess(data));
|
|
||||||
routerHistory.push(`/groups/${data.id}`);
|
|
||||||
}).catch(err => dispatch(createFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const createRequest = (id?: string) => ({
|
|
||||||
type: GROUP_CREATE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createSuccess = (group: APIEntity) => ({
|
|
||||||
type: GROUP_CREATE_SUCCESS,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createFail = (error: AxiosError) => ({
|
|
||||||
type: GROUP_CREATE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const update = (groupId: string, title: string, description: string, coverImage: File, routerHistory: History) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(updateRequest(groupId));
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('title', title);
|
|
||||||
formData.append('description', description);
|
|
||||||
|
|
||||||
if (coverImage !== null) {
|
|
||||||
formData.append('cover_image', coverImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
api(getState).put(`/api/v1/groups/${groupId}`, formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
|
||||||
dispatch(updateSuccess(data));
|
|
||||||
routerHistory.push(`/groups/${data.id}`);
|
|
||||||
}).catch(err => dispatch(updateFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateRequest = (id: string) => ({
|
|
||||||
type: GROUP_UPDATE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateSuccess = (group: APIEntity) => ({
|
|
||||||
type: GROUP_UPDATE_SUCCESS,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateFail = (error: AxiosError) => ({
|
|
||||||
type: GROUP_UPDATE_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const changeValue = (field: string, value: string | File) => ({
|
|
||||||
type: GROUP_EDITOR_VALUE_CHANGE,
|
|
||||||
field,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
|
|
||||||
const reset = () => ({
|
|
||||||
type: GROUP_EDITOR_RESET,
|
|
||||||
});
|
|
||||||
|
|
||||||
const setUp = (group: string) => ({
|
|
||||||
type: GROUP_EDITOR_SETUP,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
export {
|
|
||||||
GROUP_CREATE_REQUEST,
|
|
||||||
GROUP_CREATE_SUCCESS,
|
|
||||||
GROUP_CREATE_FAIL,
|
|
||||||
GROUP_UPDATE_REQUEST,
|
|
||||||
GROUP_UPDATE_SUCCESS,
|
|
||||||
GROUP_UPDATE_FAIL,
|
|
||||||
GROUP_EDITOR_VALUE_CHANGE,
|
|
||||||
GROUP_EDITOR_RESET,
|
|
||||||
GROUP_EDITOR_SETUP,
|
|
||||||
submit,
|
|
||||||
create,
|
|
||||||
createRequest,
|
|
||||||
createSuccess,
|
|
||||||
createFail,
|
|
||||||
update,
|
|
||||||
updateRequest,
|
|
||||||
updateSuccess,
|
|
||||||
updateFail,
|
|
||||||
changeValue,
|
|
||||||
reset,
|
|
||||||
setUp,
|
|
||||||
};
|
|
@ -1,550 +0,0 @@
|
|||||||
import { AxiosError } from 'axios';
|
|
||||||
|
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth';
|
|
||||||
|
|
||||||
import api, { getLinks } from '../api';
|
|
||||||
|
|
||||||
import { fetchRelationships } from './accounts';
|
|
||||||
import { importFetchedAccounts } from './importer';
|
|
||||||
|
|
||||||
import type { AppDispatch, RootState } from 'soapbox/store';
|
|
||||||
import type { APIEntity } from 'soapbox/types/entities';
|
|
||||||
|
|
||||||
const GROUP_FETCH_REQUEST = 'GROUP_FETCH_REQUEST';
|
|
||||||
const GROUP_FETCH_SUCCESS = 'GROUP_FETCH_SUCCESS';
|
|
||||||
const GROUP_FETCH_FAIL = 'GROUP_FETCH_FAIL';
|
|
||||||
|
|
||||||
const GROUP_RELATIONSHIPS_FETCH_REQUEST = 'GROUP_RELATIONSHIPS_FETCH_REQUEST';
|
|
||||||
const GROUP_RELATIONSHIPS_FETCH_SUCCESS = 'GROUP_RELATIONSHIPS_FETCH_SUCCESS';
|
|
||||||
const GROUP_RELATIONSHIPS_FETCH_FAIL = 'GROUP_RELATIONSHIPS_FETCH_FAIL';
|
|
||||||
|
|
||||||
const GROUPS_FETCH_REQUEST = 'GROUPS_FETCH_REQUEST';
|
|
||||||
const GROUPS_FETCH_SUCCESS = 'GROUPS_FETCH_SUCCESS';
|
|
||||||
const GROUPS_FETCH_FAIL = 'GROUPS_FETCH_FAIL';
|
|
||||||
|
|
||||||
const GROUP_JOIN_REQUEST = 'GROUP_JOIN_REQUEST';
|
|
||||||
const GROUP_JOIN_SUCCESS = 'GROUP_JOIN_SUCCESS';
|
|
||||||
const GROUP_JOIN_FAIL = 'GROUP_JOIN_FAIL';
|
|
||||||
|
|
||||||
const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST';
|
|
||||||
const GROUP_LEAVE_SUCCESS = 'GROUP_LEAVE_SUCCESS';
|
|
||||||
const GROUP_LEAVE_FAIL = 'GROUP_LEAVE_FAIL';
|
|
||||||
|
|
||||||
const GROUP_MEMBERS_FETCH_REQUEST = 'GROUP_MEMBERS_FETCH_REQUEST';
|
|
||||||
const GROUP_MEMBERS_FETCH_SUCCESS = 'GROUP_MEMBERS_FETCH_SUCCESS';
|
|
||||||
const GROUP_MEMBERS_FETCH_FAIL = 'GROUP_MEMBERS_FETCH_FAIL';
|
|
||||||
|
|
||||||
const GROUP_MEMBERS_EXPAND_REQUEST = 'GROUP_MEMBERS_EXPAND_REQUEST';
|
|
||||||
const GROUP_MEMBERS_EXPAND_SUCCESS = 'GROUP_MEMBERS_EXPAND_SUCCESS';
|
|
||||||
const GROUP_MEMBERS_EXPAND_FAIL = 'GROUP_MEMBERS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST = 'GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_FETCH_FAIL = 'GROUP_REMOVED_ACCOUNTS_FETCH_FAIL';
|
|
||||||
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST = 'GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL = 'GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL';
|
|
||||||
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL = 'GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL';
|
|
||||||
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST = 'GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS = 'GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS';
|
|
||||||
const GROUP_REMOVED_ACCOUNTS_CREATE_FAIL = 'GROUP_REMOVED_ACCOUNTS_CREATE_FAIL';
|
|
||||||
|
|
||||||
const GROUP_REMOVE_STATUS_REQUEST = 'GROUP_REMOVE_STATUS_REQUEST';
|
|
||||||
const GROUP_REMOVE_STATUS_SUCCESS = 'GROUP_REMOVE_STATUS_SUCCESS';
|
|
||||||
const GROUP_REMOVE_STATUS_FAIL = 'GROUP_REMOVE_STATUS_FAIL';
|
|
||||||
|
|
||||||
const fetchGroup = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchGroupRelationships([id]));
|
|
||||||
|
|
||||||
if (getState().groups.get(id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchGroupRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/groups/${id}`)
|
|
||||||
.then(({ data }) => dispatch(fetchGroupSuccess(data)))
|
|
||||||
.catch(err => dispatch(fetchGroupFail(id, err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchGroupRequest = (id: string) => ({
|
|
||||||
type: GROUP_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupSuccess = (group: APIEntity) => ({
|
|
||||||
type: GROUP_FETCH_SUCCESS,
|
|
||||||
group,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupRelationships = (groupIds: string[]) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const loadedRelationships = getState().group_relationships;
|
|
||||||
const newGroupIds = groupIds.filter(id => loadedRelationships.get(id, null) === null);
|
|
||||||
|
|
||||||
if (newGroupIds.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchGroupRelationshipsRequest(newGroupIds));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/groups/${newGroupIds[0]}/relationships?${newGroupIds.map(id => `id[]=${id}`).join('&')}`).then(response => {
|
|
||||||
dispatch(fetchGroupRelationshipsSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchGroupRelationshipsFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchGroupRelationshipsRequest = (ids: string[]) => ({
|
|
||||||
type: GROUP_RELATIONSHIPS_FETCH_REQUEST,
|
|
||||||
ids,
|
|
||||||
skipLoading: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupRelationshipsSuccess = (relationships: APIEntity[]) => ({
|
|
||||||
type: GROUP_RELATIONSHIPS_FETCH_SUCCESS,
|
|
||||||
relationships,
|
|
||||||
skipLoading: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupRelationshipsFail = (error: AxiosError) => ({
|
|
||||||
type: GROUP_RELATIONSHIPS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
skipLoading: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroups = (tab: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchGroupsRequest());
|
|
||||||
|
|
||||||
api(getState).get('/api/v1/groups?tab=' + tab)
|
|
||||||
.then(({ data }) => {
|
|
||||||
dispatch(fetchGroupsSuccess(data, tab));
|
|
||||||
dispatch(fetchGroupRelationships(data.map((item: APIEntity) => item.id)));
|
|
||||||
})
|
|
||||||
.catch(err => dispatch(fetchGroupsFail(err)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchGroupsRequest = () => ({
|
|
||||||
type: GROUPS_FETCH_REQUEST,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupsSuccess = (groups: APIEntity[], tab: string) => ({
|
|
||||||
type: GROUPS_FETCH_SUCCESS,
|
|
||||||
groups,
|
|
||||||
tab,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchGroupsFail = (error: AxiosError) => ({
|
|
||||||
type: GROUPS_FETCH_FAIL,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const joinGroup = (id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(joinGroupRequest(id));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/groups/${id}/accounts`).then(response => {
|
|
||||||
dispatch(joinGroupSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(joinGroupFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const leaveGroup = (id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(leaveGroupRequest(id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/groups/${id}/accounts`).then(response => {
|
|
||||||
dispatch(leaveGroupSuccess(response.data));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(leaveGroupFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const joinGroupRequest = (id: string) => ({
|
|
||||||
type: GROUP_JOIN_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const joinGroupSuccess = (relationship: APIEntity) => ({
|
|
||||||
type: GROUP_JOIN_SUCCESS,
|
|
||||||
relationship,
|
|
||||||
});
|
|
||||||
|
|
||||||
const joinGroupFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_JOIN_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const leaveGroupRequest = (id: string) => ({
|
|
||||||
type: GROUP_LEAVE_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const leaveGroupSuccess = (relationship: APIEntity) => ({
|
|
||||||
type: GROUP_LEAVE_SUCCESS,
|
|
||||||
relationship,
|
|
||||||
});
|
|
||||||
|
|
||||||
const leaveGroupFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_LEAVE_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchMembers = (id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchMembersRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/groups/${id}/accounts`).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(response.data));
|
|
||||||
dispatch(fetchMembersSuccess(id, response.data, next ? next.uri : null));
|
|
||||||
dispatch(fetchRelationships(response.data.map((item: APIEntity) => item.id)));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchMembersFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchMembersRequest = (id: string) => ({
|
|
||||||
type: GROUP_MEMBERS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchMembersSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
|
||||||
type: GROUP_MEMBERS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchMembersFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_MEMBERS_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expandMembers = (id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().user_lists.groups.get(id)!.next;
|
|
||||||
|
|
||||||
if (url === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandMembersRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(response.data));
|
|
||||||
dispatch(expandMembersSuccess(id, response.data, next ? next.uri : null));
|
|
||||||
dispatch(fetchRelationships(response.data.map((item: APIEntity) => item.id)));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(expandMembersFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const expandMembersRequest = (id: string) => ({
|
|
||||||
type: GROUP_MEMBERS_EXPAND_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expandMembersSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
|
||||||
type: GROUP_MEMBERS_EXPAND_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expandMembersFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_MEMBERS_EXPAND_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchRemovedAccounts = (id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(fetchRemovedAccountsRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(`/api/v1/groups/${id}/removed_accounts`).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(response.data));
|
|
||||||
dispatch(fetchRemovedAccountsSuccess(id, response.data, next ? next.uri : null));
|
|
||||||
dispatch(fetchRelationships(response.data.map((item: APIEntity) => item.id)));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(fetchRemovedAccountsFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchRemovedAccountsRequest = (id: string) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchRemovedAccountsSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
const fetchRemovedAccountsFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_FETCH_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expandRemovedAccounts = (id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
const url = getState().user_lists.groups_removed_accounts.get(id)!.next;
|
|
||||||
|
|
||||||
if (url === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(expandRemovedAccountsRequest(id));
|
|
||||||
|
|
||||||
api(getState).get(url).then(response => {
|
|
||||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(response.data));
|
|
||||||
dispatch(expandRemovedAccountsSuccess(id, response.data, next ? next.uri : null));
|
|
||||||
dispatch(fetchRelationships(response.data.map((item: APIEntity) => item.id)));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(expandRemovedAccountsFail(id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const expandRemovedAccountsRequest = (id: string) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expandRemovedAccountsSuccess = (id: string, accounts: APIEntity[], next: string | null) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
|
|
||||||
id,
|
|
||||||
accounts,
|
|
||||||
next,
|
|
||||||
});
|
|
||||||
|
|
||||||
const expandRemovedAccountsFail = (id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeRemovedAccount = (groupId: string, id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(removeRemovedAccountRequest(groupId, id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/groups/${groupId}/removed_accounts?account_id=${id}`).then(response => {
|
|
||||||
dispatch(removeRemovedAccountSuccess(groupId, id));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(removeRemovedAccountFail(groupId, id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeRemovedAccountRequest = (groupId: string, id: string) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeRemovedAccountSuccess = (groupId: string, id: string) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const removeRemovedAccountFail = (groupId: string, id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createRemovedAccount = (groupId: string, id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(createRemovedAccountRequest(groupId, id));
|
|
||||||
|
|
||||||
api(getState).post(`/api/v1/groups/${groupId}/removed_accounts?account_id=${id}`).then(response => {
|
|
||||||
dispatch(createRemovedAccountSuccess(groupId, id));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(createRemovedAccountFail(groupId, id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const createRemovedAccountRequest = (groupId: string, id: string) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createRemovedAccountSuccess = (groupId: string, id: string) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createRemovedAccountFail = (groupId: string, id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_REMOVED_ACCOUNTS_CREATE_FAIL,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
const groupRemoveStatus = (groupId: string, id: string) =>
|
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
|
||||||
if (!isLoggedIn(getState)) return;
|
|
||||||
|
|
||||||
dispatch(groupRemoveStatusRequest(groupId, id));
|
|
||||||
|
|
||||||
api(getState).delete(`/api/v1/groups/${groupId}/statuses/${id}`).then(response => {
|
|
||||||
dispatch(groupRemoveStatusSuccess(groupId, id));
|
|
||||||
}).catch(error => {
|
|
||||||
dispatch(groupRemoveStatusFail(groupId, id, error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const groupRemoveStatusRequest = (groupId: string, id: string) => ({
|
|
||||||
type: GROUP_REMOVE_STATUS_REQUEST,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const groupRemoveStatusSuccess = (groupId: string, id: string) => ({
|
|
||||||
type: GROUP_REMOVE_STATUS_SUCCESS,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
|
|
||||||
const groupRemoveStatusFail = (groupId: string, id: string, error: AxiosError) => ({
|
|
||||||
type: GROUP_REMOVE_STATUS_FAIL,
|
|
||||||
groupId,
|
|
||||||
id,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
|
|
||||||
export {
|
|
||||||
GROUP_FETCH_REQUEST,
|
|
||||||
GROUP_FETCH_SUCCESS,
|
|
||||||
GROUP_FETCH_FAIL,
|
|
||||||
GROUP_RELATIONSHIPS_FETCH_REQUEST,
|
|
||||||
GROUP_RELATIONSHIPS_FETCH_SUCCESS,
|
|
||||||
GROUP_RELATIONSHIPS_FETCH_FAIL,
|
|
||||||
GROUPS_FETCH_REQUEST,
|
|
||||||
GROUPS_FETCH_SUCCESS,
|
|
||||||
GROUPS_FETCH_FAIL,
|
|
||||||
GROUP_JOIN_REQUEST,
|
|
||||||
GROUP_JOIN_SUCCESS,
|
|
||||||
GROUP_JOIN_FAIL,
|
|
||||||
GROUP_LEAVE_REQUEST,
|
|
||||||
GROUP_LEAVE_SUCCESS,
|
|
||||||
GROUP_LEAVE_FAIL,
|
|
||||||
GROUP_MEMBERS_FETCH_REQUEST,
|
|
||||||
GROUP_MEMBERS_FETCH_SUCCESS,
|
|
||||||
GROUP_MEMBERS_FETCH_FAIL,
|
|
||||||
GROUP_MEMBERS_EXPAND_REQUEST,
|
|
||||||
GROUP_MEMBERS_EXPAND_SUCCESS,
|
|
||||||
GROUP_MEMBERS_EXPAND_FAIL,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_FETCH_REQUEST,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_FETCH_SUCCESS,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_FETCH_FAIL,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_EXPAND_REQUEST,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_EXPAND_SUCCESS,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_EXPAND_FAIL,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_REMOVE_REQUEST,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_REMOVE_SUCCESS,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_REMOVE_FAIL,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_CREATE_REQUEST,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_CREATE_SUCCESS,
|
|
||||||
GROUP_REMOVED_ACCOUNTS_CREATE_FAIL,
|
|
||||||
GROUP_REMOVE_STATUS_REQUEST,
|
|
||||||
GROUP_REMOVE_STATUS_SUCCESS,
|
|
||||||
GROUP_REMOVE_STATUS_FAIL,
|
|
||||||
fetchGroup,
|
|
||||||
fetchGroupRequest,
|
|
||||||
fetchGroupSuccess,
|
|
||||||
fetchGroupFail,
|
|
||||||
fetchGroupRelationships,
|
|
||||||
fetchGroupRelationshipsRequest,
|
|
||||||
fetchGroupRelationshipsSuccess,
|
|
||||||
fetchGroupRelationshipsFail,
|
|
||||||
fetchGroups,
|
|
||||||
fetchGroupsRequest,
|
|
||||||
fetchGroupsSuccess,
|
|
||||||
fetchGroupsFail,
|
|
||||||
joinGroup,
|
|
||||||
leaveGroup,
|
|
||||||
joinGroupRequest,
|
|
||||||
joinGroupSuccess,
|
|
||||||
joinGroupFail,
|
|
||||||
leaveGroupRequest,
|
|
||||||
leaveGroupSuccess,
|
|
||||||
leaveGroupFail,
|
|
||||||
fetchMembers,
|
|
||||||
fetchMembersRequest,
|
|
||||||
fetchMembersSuccess,
|
|
||||||
fetchMembersFail,
|
|
||||||
expandMembers,
|
|
||||||
expandMembersRequest,
|
|
||||||
expandMembersSuccess,
|
|
||||||
expandMembersFail,
|
|
||||||
fetchRemovedAccounts,
|
|
||||||
fetchRemovedAccountsRequest,
|
|
||||||
fetchRemovedAccountsSuccess,
|
|
||||||
fetchRemovedAccountsFail,
|
|
||||||
expandRemovedAccounts,
|
|
||||||
expandRemovedAccountsRequest,
|
|
||||||
expandRemovedAccountsSuccess,
|
|
||||||
expandRemovedAccountsFail,
|
|
||||||
removeRemovedAccount,
|
|
||||||
removeRemovedAccountRequest,
|
|
||||||
removeRemovedAccountSuccess,
|
|
||||||
removeRemovedAccountFail,
|
|
||||||
createRemovedAccount,
|
|
||||||
createRemovedAccountRequest,
|
|
||||||
createRemovedAccountSuccess,
|
|
||||||
createRemovedAccountFail,
|
|
||||||
groupRemoveStatus,
|
|
||||||
groupRemoveStatusRequest,
|
|
||||||
groupRemoveStatusSuccess,
|
|
||||||
groupRemoveStatusFail,
|
|
||||||
};
|
|
@ -1,4 +1,4 @@
|
|||||||
import { createPushSubscription, updatePushSubscription } from 'soapbox/actions/push_subscriptions';
|
import { createPushSubscription, updatePushSubscription } from 'soapbox/actions/push-subscriptions';
|
||||||
import { pushNotificationsSetting } from 'soapbox/settings';
|
import { pushNotificationsSetting } from 'soapbox/settings';
|
||||||
import { getVapidKey } from 'soapbox/utils/auth';
|
import { getVapidKey } from 'soapbox/utils/auth';
|
||||||
import { decode as decodeBase64 } from 'soapbox/utils/base64';
|
import { decode as decodeBase64 } from 'soapbox/utils/base64';
|
@ -0,0 +1,75 @@
|
|||||||
|
import api, { getLinks } from '../api';
|
||||||
|
|
||||||
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
import type { AppDispatch, RootState } from 'soapbox/store';
|
||||||
|
|
||||||
|
export const STATUS_QUOTES_FETCH_REQUEST = 'STATUS_QUOTES_FETCH_REQUEST';
|
||||||
|
export const STATUS_QUOTES_FETCH_SUCCESS = 'STATUS_QUOTES_FETCH_SUCCESS';
|
||||||
|
export const STATUS_QUOTES_FETCH_FAIL = 'STATUS_QUOTES_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const STATUS_QUOTES_EXPAND_REQUEST = 'STATUS_QUOTES_EXPAND_REQUEST';
|
||||||
|
export const STATUS_QUOTES_EXPAND_SUCCESS = 'STATUS_QUOTES_EXPAND_SUCCESS';
|
||||||
|
export const STATUS_QUOTES_EXPAND_FAIL = 'STATUS_QUOTES_EXPAND_FAIL';
|
||||||
|
|
||||||
|
const noOp = () => new Promise(f => f(null));
|
||||||
|
|
||||||
|
export const fetchStatusQuotes = (statusId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
if (getState().status_lists.getIn([`quotes:${statusId}`, 'isLoading'])) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
statusId,
|
||||||
|
type: STATUS_QUOTES_FETCH_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
return api(getState).get(`/api/v1/pleroma/statuses/${statusId}/quotes`).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
return dispatch({
|
||||||
|
type: STATUS_QUOTES_FETCH_SUCCESS,
|
||||||
|
statusId,
|
||||||
|
statuses: response.data,
|
||||||
|
next: next ? next.uri : null,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_FETCH_FAIL,
|
||||||
|
statusId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const expandStatusQuotes = (statusId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const url = getState().status_lists.getIn([`quotes:${statusId}`, 'next'], null) as string | null;
|
||||||
|
|
||||||
|
if (url === null || getState().status_lists.getIn([`quotes:${statusId}`, 'isLoading'])) {
|
||||||
|
return dispatch(noOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_EXPAND_REQUEST,
|
||||||
|
statusId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
dispatch(importFetchedStatuses(response.data));
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_EXPAND_SUCCESS,
|
||||||
|
statusId,
|
||||||
|
statuses: response.data,
|
||||||
|
next: next ? next.uri : null,
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({
|
||||||
|
type: STATUS_QUOTES_EXPAND_FAIL,
|
||||||
|
statusId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
// @preval
|
// @preval
|
||||||
/**
|
/**
|
||||||
* Build config: configuration set at build time.
|
* Build config: configuration set at build time.
|
||||||
* @module soapbox/build_config
|
* @module soapbox/build-config
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const trim = require('lodash/trim');
|
const trim = require('lodash/trim');
|
@ -1,21 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare numerical primary keys represented as strings.
|
|
||||||
* For example, '10' (as a string) is considered less than '9'
|
|
||||||
* when sorted alphabetically. So compare string length first.
|
|
||||||
*
|
|
||||||
* - `0`: id1 == id2
|
|
||||||
* - `1`: id1 > id2
|
|
||||||
* - `-1`: id1 < id2
|
|
||||||
*/
|
|
||||||
export default function compareId(id1: string, id2: string) {
|
|
||||||
if (id1 === id2) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (id1.length === id2.length) {
|
|
||||||
return id1 > id2 ? 1 : -1;
|
|
||||||
} else {
|
|
||||||
return id1.length > id2.length ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { render, screen } from '../../jest/test-helpers';
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
import AutosuggestEmoji from '../autosuggest_emoji';
|
import AutosuggestEmoji from '../autosuggest-emoji';
|
||||||
|
|
||||||
describe('<AutosuggestEmoji />', () => {
|
describe('<AutosuggestEmoji />', () => {
|
||||||
it('renders native emoji', () => {
|
it('renders native emoji', () => {
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { render, screen } from '../../jest/test-helpers';
|
import { render, screen } from '../../jest/test-helpers';
|
||||||
import EmojiSelector from '../emoji_selector';
|
import EmojiSelector from '../emoji-selector';
|
||||||
|
|
||||||
describe('<EmojiSelector />', () => {
|
describe('<EmojiSelector />', () => {
|
||||||
it('renders correctly', () => {
|
it('renders correctly', () => {
|
@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { render, screen, rootState } from '../../jest/test-helpers';
|
||||||
|
import { normalizeStatus, normalizeAccount } from '../../normalizers';
|
||||||
|
import Status from '../status';
|
||||||
|
|
||||||
|
import type { ReducerStatus } from 'soapbox/reducers/statuses';
|
||||||
|
|
||||||
|
const account = normalizeAccount({
|
||||||
|
id: '1',
|
||||||
|
acct: 'alex',
|
||||||
|
});
|
||||||
|
|
||||||
|
const status = normalizeStatus({
|
||||||
|
id: '1',
|
||||||
|
account,
|
||||||
|
content: 'hello world',
|
||||||
|
contentHtml: 'hello world',
|
||||||
|
}) as ReducerStatus;
|
||||||
|
|
||||||
|
describe('<Status />', () => {
|
||||||
|
const state = rootState.setIn(['accounts', '1'], account);
|
||||||
|
|
||||||
|
it('renders content', () => {
|
||||||
|
render(<Status status={status} />, undefined, state);
|
||||||
|
screen.getByText(/hello world/i);
|
||||||
|
expect(screen.getByTestId('status')).toHaveTextContent(/hello world/i);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('the Status Action Bar', () => {
|
||||||
|
it('is rendered', () => {
|
||||||
|
render(<Status status={status} />, undefined, state);
|
||||||
|
expect(screen.getByTestId('status-action-bar')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is not rendered if status is under review', () => {
|
||||||
|
const inReviewStatus = normalizeStatus({ ...status, visibility: 'self' });
|
||||||
|
render(<Status status={inReviewStatus as ReducerStatus} />, undefined, state);
|
||||||
|
expect(screen.queryAllByTestId('status-action-bar')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|