import {
PayloadAction,
createAsyncThunk,
createSelector,
createSlice,
} from '@reduxjs/toolkit';
import { queryPassportContract } from 'src/soft.js/api/passport';
import { Citizenship } from 'src/types/citizenship';
import { CyberClient } from '@cybercongress/cyber-js';
import { RootState } from 'src/redux/store';
import { AppThunk } from 'src/redux/types';
import { selectCurrentAddress } from 'src/redux/features/pocket';
import { Accounts } from 'src/types/defaultAccount';
import { PASSPORT_NOT_EXISTS_ERROR } from './constants';
export type SliceState = {
// address
[key in string]?: {
data?: Citizenship | null;
loading: boolean;
};
};
const initialState: SliceState = {};
export function getCommunityPassports(queryClient: CyberClient): AppThunk {
return (dispatch, getState) => {
const {
backend: { community },
passports,
} = getState();
const { following, followers, friends } = community;
[...friends, ...following, ...followers].forEach((address) => {
const passport = passports[address];
if (!passport?.data && !passport?.loading) {
dispatch(getPassport({ address, queryClient }));
}
});
};
}
export function getAccountsPassports(queryClient: CyberClient): AppThunk {
return (dispatch, getState) => {
const { pocket, passports } = getState();
const { accounts } = pocket;
if (accounts === null) {
return;
}
Object.keys(accounts).forEach((key) => {
const item = accounts[key];
const address = item.cyber.bech32;
const passport = passports[address];
if (!passport?.data && !passport?.loading) {
dispatch(getPassport({ address, queryClient }));
}
});
};
}
const getPassport = createAsyncThunk(
'passports/getPassport',
async ({
address,
queryClient,
}: {
address: string;
queryClient: CyberClient;
}) => {
const response = await queryPassportContract(
{
active_passport: {
address,
},
},
queryClient
);
return response;
}
);
const slice = createSlice({
name: 'passports',
initialState,
reducers: {
addAddress: (
state,
{
payload: { address, currentAddress },
}: PayloadAction<{
address: string;
currentAddress: string;
}>
) => {
if (
!(
state[currentAddress]?.data &&
state[currentAddress].data.extension.addresses
)
) {
return;
}
state[currentAddress].data.extension.addresses.push({
label: null,
address,
});
},
deleteAddress: (
state,
{
payload: { address, currentAddress },
}: PayloadAction<{
address: string;
currentAddress: string;
}>
) => {
if (
!(
state[currentAddress]?.data &&
state[currentAddress].data.extension.addresses
)
) {
return;
}
state[currentAddress].data.extension.addresses = state[
currentAddress
].data.extension.addresses.filter((item) => item.address !== address);
},
},
extraReducers: (builder) => {
builder.addCase(getPassport.pending, (state, action) => {
state[action.meta.arg.address] = {
loading: true,
};
});
builder.addCase(getPassport.fulfilled, (state, action) => {
Object.assign(state[action.meta.arg.address]!, {
loading: false,
data: action.payload,
});
});
builder.addCase(getPassport.rejected, (state, action) => {
if (action.error.message !== PASSPORT_NOT_EXISTS_ERROR) {
console.error(action);
}
Object.assign(state[action.meta.arg.address]!, {
loading: false,
data: null,
});
});
},
});
export const selectCommunityPassports = createSelector(
(state: RootState) => state.backend.community,
(state: RootState) => state.passports,
(community, passports) => {
const { following, followers, friends } = community;
function process(addresses: string[]) {
return addresses.reduce<SliceState>((acc, value) => {
acc[value] = passports[value];
return acc;
}, {});
}
return {
following: process(following),
followers: process(followers),
friends: process(friends),
};
}
);
export const selectAccountsPassports = createSelector(
(state: RootState) => state.pocket.accounts,
(state: RootState) => state.passports,
(accounts, passports) => {
function process(addresses: Accounts) {
return Object.keys(addresses).reduce<SliceState>((acc, key) => {
const item = addresses[key];
const address = item.cyber.bech32;
acc[address] = passports[address];
return acc;
}, {});
}
return {
accounts: accounts ? process(accounts) : {},
};
}
);
export const selectCurrentPassport = createSelector(
selectCurrentAddress,
(state: RootState) => state.passports,
(address, passports) => (address ? passports[address] : undefined)
);
export const { deleteAddress, addAddress } = slice.actions;
export { getPassport };
export default slice.reducer;