Skip to content

Commit

Permalink
[Glitch] Convert actions/account_notes into Typescript
Browse files Browse the repository at this point in the history
Port bd06c13 to glitch-soc

Signed-off-by: Claire <[email protected]>
  • Loading branch information
renchap authored and ClearlyClaire committed Dec 3, 2023
1 parent 335cfab commit fcb3db9
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 161 deletions.
37 changes: 0 additions & 37 deletions app/javascript/flavours/glitch/actions/account_notes.js

This file was deleted.

18 changes: 18 additions & 0 deletions app/javascript/flavours/glitch/actions/account_notes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createAppAsyncThunk } from 'mastodon/store/typed_functions';

import api from '../api';

export const submitAccountNote = createAppAsyncThunk(
'account_note/submit',
async (args: { id: string; value: string }, { getState }) => {
// TODO: replace `unknown` with `ApiRelationshipJSON` when it is merged
const response = await api(getState).post<unknown>(
`/api/v1/accounts/${args.id}/note`,
{
comment: args.value,
},
);

return { relationship: response.data };
},
);
75 changes: 0 additions & 75 deletions app/javascript/flavours/glitch/api.js

This file was deleted.

63 changes: 63 additions & 0 deletions app/javascript/flavours/glitch/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { AxiosResponse, RawAxiosRequestHeaders } from 'axios';
import axios from 'axios';
import LinkHeader from 'http-link-header';

import ready from './ready';
import type { GetState } from './store';

export const getLinks = (response: AxiosResponse) => {
const value = response.headers.link as string | undefined;

if (!value) {
return new LinkHeader();
}

return LinkHeader.parse(value);
};

const csrfHeader: RawAxiosRequestHeaders = {};

const setCSRFHeader = () => {
const csrfToken = document.querySelector<HTMLMetaElement>(
'meta[name=csrf-token]',
);

if (csrfToken) {
csrfHeader['X-CSRF-Token'] = csrfToken.content;
}
};

void ready(setCSRFHeader);

const authorizationHeaderFromState = (getState?: GetState) => {
const accessToken =
getState && (getState().meta.get('access_token', '') as string);

if (!accessToken) {
return {};
}

return {
Authorization: `Bearer ${accessToken}`,
} as RawAxiosRequestHeaders;
};

// eslint-disable-next-line import/no-default-export
export default function api(getState: GetState) {
return axios.create({
headers: {
...csrfHeader,
...authorizationHeaderFromState(getState),
},

transformResponse: [
function (data: unknown) {
try {
return JSON.parse(data as string) as unknown;
} catch {
return data;
}
},
],
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const mapStateToProps = (state, { account }) => ({
const mapDispatchToProps = (dispatch, { account }) => ({

onSave (value) {
dispatch(submitAccountNote(account.get('id'), value));
dispatch(submitAccountNote({ id: account.get('id'), value}));
},

});
Expand Down
6 changes: 3 additions & 3 deletions app/javascript/flavours/glitch/reducers/relationships.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Map as ImmutableMap, fromJS } from 'immutable';

import {
ACCOUNT_NOTE_SUBMIT_SUCCESS,
submitAccountNote,
} from '../actions/account_notes';
import {
ACCOUNT_FOLLOW_SUCCESS,
Expand Down Expand Up @@ -73,10 +73,10 @@ export default function relationships(state = initialState, action) {
case ACCOUNT_UNMUTE_SUCCESS:
case ACCOUNT_PIN_SUCCESS:
case ACCOUNT_UNPIN_SUCCESS:
case ACCOUNT_NOTE_SUBMIT_SUCCESS:
return normalizeRelationship(state, action.relationship);
case RELATIONSHIPS_FETCH_SUCCESS:
return normalizeRelationships(state, action.relationships);
case submitAccountNote.fulfilled:
return normalizeRelationship(state, action.payload.relationship);
case DOMAIN_BLOCK_SUCCESS:
return setDomainBlocking(state, action.accounts, true);
case DOMAIN_UNBLOCK_SUCCESS:
Expand Down
53 changes: 8 additions & 45 deletions app/javascript/flavours/glitch/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,8 @@
import type { TypedUseSelectorHook } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { configureStore } from '@reduxjs/toolkit';

import { rootReducer } from '../reducers';

import { errorsMiddleware } from './middlewares/errors';
import { loadingBarMiddleware } from './middlewares/loading_bar';
import { soundsMiddleware } from './middlewares/sounds';

export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
// In development, Redux Toolkit enables 2 default middlewares to detect
// common issues with states. Unfortunately, our use of ImmutableJS for state
// triggers both, so lets disable them until our state is fully refactored

// https://redux-toolkit.js.org/api/serializabilityMiddleware
// This checks recursively that every values in the state are serializable in JSON
// Which is not the case, as we use ImmutableJS structures, but also File objects
serializableCheck: false,

// https://redux-toolkit.js.org/api/immutabilityMiddleware
// This checks recursively if every value in the state is immutable (ie, a JS primitive type)
// But this is not the case, as our Root State is an ImmutableJS map, which is an object
immutableCheck: false,
})
.concat(
loadingBarMiddleware({
promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],
}),
)
.concat(errorsMiddleware)
.concat(soundsMiddleware()),
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof rootReducer>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;

export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export { store } from './store';
export type { GetState, AppDispatch, RootState } from './store';

export {
createAppAsyncThunk,
useAppDispatch,
useAppSelector,
} from './typed_functions';
40 changes: 40 additions & 0 deletions app/javascript/flavours/glitch/store/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { configureStore } from '@reduxjs/toolkit';

import { rootReducer } from '../reducers';

import { errorsMiddleware } from './middlewares/errors';
import { loadingBarMiddleware } from './middlewares/loading_bar';
import { soundsMiddleware } from './middlewares/sounds';

export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
// In development, Redux Toolkit enables 2 default middlewares to detect
// common issues with states. Unfortunately, our use of ImmutableJS for state
// triggers both, so lets disable them until our state is fully refactored

// https://redux-toolkit.js.org/api/serializabilityMiddleware
// This checks recursively that every values in the state are serializable in JSON
// Which is not the case, as we use ImmutableJS structures, but also File objects
serializableCheck: false,

// https://redux-toolkit.js.org/api/immutabilityMiddleware
// This checks recursively if every value in the state is immutable (ie, a JS primitive type)
// But this is not the case, as our Root State is an ImmutableJS map, which is an object
immutableCheck: false,
})
.concat(
loadingBarMiddleware({
promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],
}),
)
.concat(errorsMiddleware)
.concat(soundsMiddleware()),
});

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof rootReducer>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
export type GetState = typeof store.getState;
16 changes: 16 additions & 0 deletions app/javascript/flavours/glitch/store/typed_functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { TypedUseSelectorHook } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { createAsyncThunk } from '@reduxjs/toolkit';

import type { AppDispatch, RootState } from './store';

export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

export const createAppAsyncThunk = createAsyncThunk.withTypes<{
state: RootState;
dispatch: AppDispatch;
rejectValue: string;
extra: { s: string; n: number };
}>();

0 comments on commit fcb3db9

Please sign in to comment.