2023-02-18 13:11:01 +03:00
|
|
|
import type { AsyncThunk, SliceCaseReducers } from '@reduxjs/toolkit';
|
|
|
|
import { createAction, createSlice } from '@reduxjs/toolkit';
|
2023-07-16 09:47:10 +03:00
|
|
|
import { createAsyncThunk } from '../../../utils/helpers/redux';
|
2023-07-24 18:30:58 +03:00
|
|
|
import type { ProblemDetailsError, ShlinkApiClient, ShlinkDomainRedirects } from '../../api-contract';
|
|
|
|
import { parseApiError } from '../../api-contract/utils';
|
2023-02-18 13:11:01 +03:00
|
|
|
import type { Domain, DomainStatus } from '../data';
|
2023-02-18 12:40:37 +03:00
|
|
|
import type { EditDomainRedirects } from './domainRedirects';
|
2020-11-25 23:05:27 +03:00
|
|
|
|
2022-11-09 20:19:07 +03:00
|
|
|
const REDUCER_PREFIX = 'shlink/domainsList';
|
2020-11-25 23:05:27 +03:00
|
|
|
|
|
|
|
export interface DomainsList {
|
2021-12-26 15:38:17 +03:00
|
|
|
domains: Domain[];
|
|
|
|
filteredDomains: Domain[];
|
2021-12-09 15:44:29 +03:00
|
|
|
defaultRedirects?: ShlinkDomainRedirects;
|
2020-11-25 23:05:27 +03:00
|
|
|
loading: boolean;
|
|
|
|
error: boolean;
|
2021-08-21 18:53:06 +03:00
|
|
|
errorData?: ProblemDetailsError;
|
2020-11-25 23:05:27 +03:00
|
|
|
}
|
|
|
|
|
2022-11-03 21:52:57 +03:00
|
|
|
interface ListDomains {
|
2021-12-26 15:38:17 +03:00
|
|
|
domains: Domain[];
|
2021-12-09 15:44:29 +03:00
|
|
|
defaultRedirects?: ShlinkDomainRedirects;
|
2022-11-03 21:52:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
interface ValidateDomain {
|
2021-12-26 15:38:17 +03:00
|
|
|
domain: string;
|
|
|
|
status: DomainStatus;
|
2022-11-03 21:52:57 +03:00
|
|
|
}
|
|
|
|
|
2020-11-25 23:05:27 +03:00
|
|
|
const initialState: DomainsList = {
|
|
|
|
domains: [],
|
2021-08-21 18:53:06 +03:00
|
|
|
filteredDomains: [],
|
2020-11-25 23:05:27 +03:00
|
|
|
loading: false,
|
|
|
|
error: false,
|
|
|
|
};
|
|
|
|
|
2022-11-04 20:56:34 +03:00
|
|
|
export const replaceRedirectsOnDomain = ({ domain, redirects }: EditDomainRedirects) =>
|
2022-03-26 14:17:42 +03:00
|
|
|
(d: Domain): Domain => (d.domain !== domain ? d : { ...d, redirects });
|
2021-12-26 15:38:17 +03:00
|
|
|
|
|
|
|
export const replaceStatusOnDomain = (domain: string, status: DomainStatus) =>
|
2022-03-26 14:17:42 +03:00
|
|
|
(d: Domain): Domain => (d.domain !== domain ? d : { ...d, status });
|
2021-08-21 18:53:06 +03:00
|
|
|
|
2022-11-04 20:56:34 +03:00
|
|
|
export const domainsListReducerCreator = (
|
2023-07-24 10:48:41 +03:00
|
|
|
apiClient: ShlinkApiClient,
|
2022-11-04 20:56:34 +03:00
|
|
|
editDomainRedirects: AsyncThunk<EditDomainRedirects, any, any>,
|
|
|
|
) => {
|
2023-07-24 10:48:41 +03:00
|
|
|
const listDomains = createAsyncThunk(`${REDUCER_PREFIX}/listDomains`, async (): Promise<ListDomains> => {
|
|
|
|
const { data, defaultRedirects } = await apiClient.listDomains();
|
2022-11-02 22:40:14 +03:00
|
|
|
|
2022-11-05 11:10:30 +03:00
|
|
|
return {
|
|
|
|
domains: data.map((domain): Domain => ({ ...domain, status: 'validating' })),
|
|
|
|
defaultRedirects,
|
|
|
|
};
|
|
|
|
});
|
2022-11-02 22:40:14 +03:00
|
|
|
|
2022-11-05 11:10:30 +03:00
|
|
|
const checkDomainHealth = createAsyncThunk(
|
2022-11-09 20:19:07 +03:00
|
|
|
`${REDUCER_PREFIX}/checkDomainHealth`,
|
2023-07-24 11:47:40 +03:00
|
|
|
async (domain: string): Promise<ValidateDomain> => {
|
2022-11-02 22:40:14 +03:00
|
|
|
try {
|
2023-07-24 11:47:40 +03:00
|
|
|
const { status } = await apiClient.health(domain);
|
2022-11-02 22:40:14 +03:00
|
|
|
return { domain, status: status === 'pass' ? 'valid' : 'invalid' };
|
|
|
|
} catch (e) {
|
|
|
|
return { domain, status: 'invalid' };
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2022-11-09 20:19:07 +03:00
|
|
|
const filterDomains = createAction<string>(`${REDUCER_PREFIX}/filterDomains`);
|
2022-11-04 18:50:03 +03:00
|
|
|
|
|
|
|
const { reducer } = createSlice<DomainsList, SliceCaseReducers<DomainsList>>({
|
2022-11-09 20:19:07 +03:00
|
|
|
name: REDUCER_PREFIX,
|
2022-11-02 22:40:14 +03:00
|
|
|
initialState,
|
2022-11-04 18:50:03 +03:00
|
|
|
reducers: {},
|
2022-11-02 22:40:14 +03:00
|
|
|
extraReducers: (builder) => {
|
|
|
|
builder.addCase(listDomains.pending, () => ({ ...initialState, loading: true }));
|
|
|
|
builder.addCase(listDomains.rejected, (_, { error }) => (
|
2022-11-03 22:51:20 +03:00
|
|
|
{ ...initialState, error: true, errorData: parseApiError(error) }
|
2022-11-02 22:40:14 +03:00
|
|
|
));
|
|
|
|
builder.addCase(listDomains.fulfilled, (_, { payload }) => (
|
|
|
|
{ ...initialState, ...payload, filteredDomains: payload.domains }
|
|
|
|
));
|
|
|
|
|
2022-11-03 22:51:20 +03:00
|
|
|
builder.addCase(checkDomainHealth.fulfilled, ({ domains, filteredDomains, ...rest }, { payload }) => ({
|
|
|
|
...rest,
|
|
|
|
domains: domains.map(replaceStatusOnDomain(payload.domain, payload.status)),
|
|
|
|
filteredDomains: filteredDomains.map(replaceStatusOnDomain(payload.domain, payload.status)),
|
|
|
|
}));
|
|
|
|
|
2022-11-04 18:50:03 +03:00
|
|
|
builder.addCase(filterDomains, (state, { payload }) => ({
|
|
|
|
...state,
|
|
|
|
filteredDomains: state.domains.filter(({ domain }) => domain.toLowerCase().match(payload.toLowerCase())),
|
|
|
|
}));
|
|
|
|
|
2022-11-04 20:56:34 +03:00
|
|
|
builder.addCase(editDomainRedirects.fulfilled, (state, { payload }) => ({
|
2022-11-03 22:51:20 +03:00
|
|
|
...state,
|
2022-11-04 20:56:34 +03:00
|
|
|
domains: state.domains.map(replaceRedirectsOnDomain(payload)),
|
|
|
|
filteredDomains: state.filteredDomains.map(replaceRedirectsOnDomain(payload)),
|
2022-11-03 22:51:20 +03:00
|
|
|
}));
|
2022-11-02 22:40:14 +03:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
|
|
reducer,
|
|
|
|
listDomains,
|
|
|
|
checkDomainHealth,
|
2022-11-04 18:50:03 +03:00
|
|
|
filterDomains,
|
2022-11-02 22:40:14 +03:00
|
|
|
};
|
|
|
|
};
|