SME-Web/src/store/slices/selectedRecipientsSlice.tsx

606 lines
23 KiB
TypeScript

// import { createSlice, PayloadAction } from '@reduxjs/toolkit';
// import { createAsyncThunk } from '@reduxjs/toolkit';
// import { toast } from 'react-toastify';
// import colors from '../../utlity/colorsArr';
// import api from '../../config/api';
// export enum recipientType {
// SIGNER = "Signer",
// INPERSONSIGNER = "InPersonSigner",
// CC = "CC"
// }
// export interface Recipient {
// id?: string;
// firstName: string;
// lastName: string;
// routingOrder: number;
// email: string;
// hostName: string;
// hostEmail: string;
// type: recipientType;
// color?: string;
// }
// export interface SelectedRecipientInt {
// recipients: Recipient[],
// signingOrder: boolean,
// transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE
// }
// interface AddRecipientArgs {
// recipientsData: Recipient[];
// accountId: string;
// transactionId: string;
// }
// export enum TRANSACTION_TEMPLATE_TOGGLE {
// TRANSACTIONS = "transactions",
// TEMPLATES = "templates"
// }
// const initialState: SelectedRecipientInt = {
// recipients: [],
// signingOrder: false,
// transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS
// };
// export const addRecipientAsync = createAsyncThunk<Recipient[], AddRecipientArgs>(
// 'selectedRecipients/addRecipientAsync',
// async ({ recipientsData, accountId, transactionId }, { rejectWithValue }) => {
// console.log(recipientsData, accountId, transactionId, "recipientsData Line 46");
// try {
// console.log(recipientsData, "recipientsData --- Line 48");
// const updateRecipientsData = recipientsData.filter((recipient, idx) => recipient.id !== null);
// const createRecipientsData = recipientsData.filter((recipient, idx) => recipient.id == null);
// console.log(updateRecipientsData, "updateRecipientsData Line 52");
// console.log(createRecipientsData, "createRecipientsData Line 53");
// const resUpdate = await api.put(
// `/api/accounts/${accountId}/transactions/${transactionId}/recipients`,
// updateRecipientsData
// );
// const resCreate = await api.post(
// `/api/accounts/${accountId}/transactions/${transactionId}/recipients`,
// createRecipientsData
// );
// if (createRecipientsData.length === 0) resCreate.data = [];
// if (updateRecipientsData.length === 0) resUpdate.data = [];
// console.log(resCreate, "resCreate");
// console.log(resUpdate, "resUpdate");
// return [...resCreate.data, ...resUpdate.data] as Recipient[];
// } catch (err: any) {
// return rejectWithValue(err.response?.data || "Failed to add recipient");
// }
// }
// );
// interface RemoveRecipientAsyncInterfaceObj {
// id?: string;
// email?: string;
// }
// interface RemoveRecipientAsyncInterface {
// recipientId: number | null;
// accountId: string;
// transactionId: string;
// email: string;
// }
// export const removeRecipientAsync = createAsyncThunk<string | number, RemoveRecipientAsyncInterface>(
// 'selectedRecipients/removeRecipientAsync',
// async (obj, { rejectWithValue }) => {
// try {
// if (obj.recipientId) {
// const res = await api.delete(`/api/accounts/${obj.accountId}/transactions/${obj.transactionId}/recipients/${obj.recipientId}`);
// console.log(res, "Line 77")
// return obj.recipientId;
// }
// return obj.email
// } catch (err: any) {
// return rejectWithValue("Failed to remove recipient");
// }
// }
// );
// export const fetchRecipients = createAsyncThunk<Recipient[], { accountId: string, transactionId: string }>(
// 'selectedRecipients/fetchRecipients',
// async ({ accountId, transactionId }, { rejectWithValue }) => {
// try {
// const response = await api.get(`/api/accounts/${accountId}/transactions/${transactionId}/recipients`);
// return response.data as Recipient[];
// } catch (err: any) {
// return rejectWithValue(err.response?.data || "Failed to fetch recipients");
// }
// }
// );
// const selectedRecipientsSlice = createSlice({
// name: 'selectedRecipients',
// initialState,
// reducers: {
// // Add a single recipient
// addRecipient: (state, action: PayloadAction<Recipient>) => {
// for (const recipient of state.recipients) {
// if (recipient.email === action.payload.email) {
// toast.dismiss();
// toast.error("Email already exists !", {
// position: "bottom-right",
// autoClose: 5000,
// hideProgressBar: false,
// closeOnClick: false,
// pauseOnHover: true,
// draggable: true,
// progress: undefined,
// theme: "light",
// });
// return state;
// }
// }
// // Adding Recipient on top if type is inPersonSigner
// console.log("Getting Type ", action.payload.type)
// if (action.payload.type === recipientType.INPERSONSIGNER) {
// state.signingOrder = true
// state.recipients = [action.payload, ...state.recipients]
// } else {
// state.recipients.push(action.payload);
// }
// },
// resetRecipients: (state) => {
// state.recipients = [];
// },
// toggleToTemplates: (state) => {
// state.transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES;
// },
// // Replace the entire selectedRecipients array
// setSelectedRecipients: (state, action: PayloadAction<Recipient[]>) => {
// for (const [index, recipient] of action.payload.entries()) {
// if ((recipient.type === recipientType.INPERSONSIGNER && index > 0) && action.payload[index - 1].type !== recipientType.INPERSONSIGNER) {
// return state;
// }
// }
// state.recipients = action.payload;
// },
// setSigningOrder: (state, action: PayloadAction<boolean>) => {
// for (const recipient of state.recipients) {
// if (recipient.type === recipientType.INPERSONSIGNER) {
// if (state.signingOrder) return state;
// state.signingOrder = true;
// return state
// }
// }
// state.signingOrder = action.payload;
// },
// // Remove Recipients
// removeSelectedRecipient: (state, action: PayloadAction<Recipient>) => {
// console.log("removeSelectedRecipient Called")
// state.recipients = state.recipients.filter((recipient) => recipient.email !== action.payload.email);
// },
// // Add Color in Recipient
// addColorsToRecipient: (state) => {
// // const colors = generateUniqueColors(state.recipients.length);
// for (const [index, recipient] of state.recipients.entries()) {
// console.log(state)
// recipient.color = colors[index]
// }
// return state;
// },
// updateRecipientOrder: (state, action: PayloadAction<{ id: string; routingOrder: number }>) => {
// console.log("recipient order called Line 159")
// const { id, routingOrder } = action.payload;
// const recipient = state.recipients.find((r) => r.id === id || r.email === id);
// if (recipient) {
// recipient.routingOrder = routingOrder;
// }
// },
// updateRecipientIds: (state, action: PayloadAction<Recipient[]>) => {
// console.log("updateRecipientIds", console.table(action.payload));
// for (const recObj of state.recipients) {
// const email = recObj.email
// for (const recObj2 of action.payload) {
// recObj.id = recObj2.id;
// }
// }
// },
// resetSelRecipient: (state) => {
// state = initialState;
// return state;
// }
// },
// extraReducers: (builder) => {
// builder
// // Fetch Recipient - START
// .addCase(fetchRecipients.pending, (state) => {
// })
// .addCase(fetchRecipients.fulfilled, (state, action: PayloadAction<Recipient[]>) => {
// // console.log("Fetched recipients successfully:", action.payload);
// // Assign colors to recipients
// const assignedRecipients = action.payload.map((recipient, index) => ({
// ...recipient,
// color: colors[index], // Cycle if more recipients than colors
// }));
// state.recipients = assignedRecipients;
// })
// .addCase(fetchRecipients.rejected, (state, action) => {
// console.error("Failed to fetch recipients:", action.payload);
// toast.error("Failed to fetch recipients", {
// position: "bottom-right",
// autoClose: 5000,
// hideProgressBar: false,
// closeOnClick: false,
// pauseOnHover: true,
// draggable: true,
// progress: undefined,
// theme: "light",
// });
// })
// // Fetch Recipient - END
// // Add Recipient - START
// .addCase(addRecipientAsync.pending, (state) => {
// })
// .addCase(addRecipientAsync.fulfilled, (state, action: PayloadAction<Recipient[]>) => {
// // Optionally avoid duplicates if needed
// console.log("addRecipientAsync Called Line 258", action.payload);
// // const newRecipients = action.payload.filter(newRec => {
// // return !state.recipients.some(existing => existing existing.id === newRec.id);
// // });
// // const newRecipients = action.payload.filter(newRec => {
// // return !state.recipients.some(existing => "id" in existing && existing.id === newRec.id);
// // });
// // // Add new recipients and assign colors
// // const startIndex = state.recipients.length;
// // newRecipients.forEach((rec, index) => {
// // rec.color = colors[startIndex + index];
// // state.recipients.push(rec);
// // });
// state.recipients = action.payload.map((recipient, index) => ({
// ...recipient,
// color: colors[index % colors.length], // Cycle through colors
// }));
// })
// .addCase(addRecipientAsync.rejected, (state, action) => {
// console.error("Failed to fetch recipients:", action.payload);
// toast.error("Failed to fetch recipients", {
// position: "bottom-right",
// autoClose: 5000,
// hideProgressBar: false,
// closeOnClick: false,
// pauseOnHover: true,
// draggable: true,
// progress: undefined,
// theme: "light",
// });
// })
// // Add Recipient - END
// // Fetch Recipient - START
// .addCase(removeRecipientAsync.pending, (state) => {
// })
// .addCase(removeRecipientAsync.fulfilled, (state, action: PayloadAction<string | number>) => {
// state.recipients = state.recipients.filter(
// (recipient) => recipient.id !== action.payload && recipient.email !== action.payload
// );
// })
// .addCase(removeRecipientAsync.rejected, (state, action) => {
// console.error("Failed to Delete recipients:", action.payload);
// toast.error("Failed to Delete recipients", {
// position: "bottom-right",
// autoClose: 5000,
// hideProgressBar: false,
// closeOnClick: false,
// pauseOnHover: true,
// draggable: true,
// progress: undefined,
// theme: "light",
// });
// })
// // Fetch Recipient - END
// }
// });
// export const { addRecipient, setSelectedRecipients, toggleToTemplates, removeSelectedRecipient, setSigningOrder, addColorsToRecipient, updateRecipientIds, resetSelRecipient, updateRecipientOrder, resetRecipients } = selectedRecipientsSlice.actions;
// export default selectedRecipientsSlice.reducer;
import { createSlice, PayloadAction, createAsyncThunk } from '@reduxjs/toolkit';
import { toast } from 'react-toastify';
import colors from '../../utlity/colorsArr';
import api from '../../config/api';
export enum recipientType {
SIGNER = "Signer",
INPERSONSIGNER = "InPersonSigner",
CC = "CC"
}
export interface Recipient {
id?: string;
firstName: string;
lastName: string;
routingOrder: number;
email: string;
hostName: string;
hostEmail: string;
type: recipientType;
color?: string;
roleName:string
}
export interface SelectedRecipientInt {
recipients: Recipient[],
signingOrder: boolean,
transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE
}
interface AddRecipientArgs {
recipientsData: Recipient[];
accountId: string;
transactionId: string;
transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE;
}
interface RemoveRecipientAsyncInterface {
recipientId: number | null;
accountId: string;
transactionId: string;
email: string;
transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE;
}
export enum TRANSACTION_TEMPLATE_TOGGLE {
TRANSACTIONS = "transactions",
TEMPLATES = "templates"
}
const initialState: SelectedRecipientInt = {
recipients: [],
signingOrder: false,
transactionTemplateToggle: TRANSACTION_TEMPLATE_TOGGLE.TRANSACTIONS
};
// 1. Add Recipient Async
export const addRecipientAsync = createAsyncThunk<
Recipient[],
{ recipientsData: Recipient[]; accountId: string; transactionId: string }
>(
'selectedRecipients/addRecipientAsync',
async ({ recipientsData, accountId, transactionId }, { rejectWithValue, getState }) => {
try {
const state = getState() as { selectedRecipients: SelectedRecipientInt };
const toggle = state.selectedRecipients.transactionTemplateToggle;
const updateRecipientsData = recipientsData.filter(recipient => recipient.id !== null);
const createRecipientsData = recipientsData.filter(recipient => recipient.id == null);
const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`;
const resUpdate = updateRecipientsData.length
? await api.put(basePath, updateRecipientsData)
: { data: [] };
const resCreate = createRecipientsData.length
? await api.post(basePath, createRecipientsData)
: { data: [] };
return [...resCreate.data, ...resUpdate.data] as Recipient[];
} catch (err: any) {
return rejectWithValue(err.response?.data || "Failed to add recipient");
}
}
);
// 2. Remove Recipient Async
export const removeRecipientAsync = createAsyncThunk<
string | number,
{ recipientId: number | null; accountId: string; transactionId: string; email: string }
>(
'selectedRecipients/removeRecipientAsync',
async ({ recipientId, accountId, transactionId, email }, { rejectWithValue, getState }) => {
try {
const state = getState() as { selectedRecipients: SelectedRecipientInt };
const toggle = state.selectedRecipients.transactionTemplateToggle;
const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`;
if (recipientId) {
await api.delete(`${basePath}/${recipientId}`);
return recipientId;
}
return email;
} catch (err: any) {
return rejectWithValue("Failed to remove recipient");
}
}
);
// 3. Fetch Recipients Async
export const fetchRecipients = createAsyncThunk<
Recipient[],
{ accountId: string; transactionId: string }
>(
'selectedRecipients/fetchRecipients',
async ({ accountId, transactionId }, { rejectWithValue, getState }) => {
try {
const state = getState() as { selectedRecipients: SelectedRecipientInt };
const toggle = state.selectedRecipients.transactionTemplateToggle;
const basePath = `/api/accounts/${accountId}/${toggle}/${transactionId}/recipients`;
const response = await api.get(basePath);
return response.data as Recipient[];
} catch (err: any) {
return rejectWithValue(err.response?.data || "Failed to fetch recipients");
}
}
);
const selectedRecipientsSlice = createSlice({
name: 'selectedRecipients',
initialState,
reducers: {
addRecipient: (state, action: PayloadAction<Recipient>) => {
for (const recipient of state.recipients) {
if (recipient.email === action.payload.email) {
toast.dismiss();
toast.error("Email already exists !", {
position: "bottom-right",
autoClose: 5000,
theme: "light",
});
return state;
}
}
if (action.payload.type === recipientType.INPERSONSIGNER) {
state.signingOrder = true;
state.recipients = [action.payload, ...state.recipients];
} else {
state.recipients.push(action.payload);
}
},
resetRecipients: (state) => {
state.recipients = [];
},
toggleToTemplates: (state) => {
state.transactionTemplateToggle = TRANSACTION_TEMPLATE_TOGGLE.TEMPLATES;
},
setSelectedRecipients: (state, action: PayloadAction<Recipient[]>) => {
for (const [index, recipient] of action.payload.entries()) {
if ((recipient.type === recipientType.INPERSONSIGNER && index > 0)
&& action.payload[index - 1].type !== recipientType.INPERSONSIGNER) {
return state;
}
}
state.recipients = action.payload;
},
setSigningOrder: (state, action: PayloadAction<boolean>) => {
for (const recipient of state.recipients) {
if (recipient.type === recipientType.INPERSONSIGNER) {
if (state.signingOrder) return state;
state.signingOrder = true;
return state;
}
}
state.signingOrder = action.payload;
},
removeSelectedRecipient: (state, action: PayloadAction<Recipient>) => {
state.recipients = state.recipients.filter((recipient) => recipient.email !== action.payload.email);
},
addColorsToRecipient: (state) => {
for (const [index, recipient] of state.recipients.entries()) {
recipient.color = colors[index];
}
return state;
},
updateRecipientOrder: (state, action: PayloadAction<{ id: string; routingOrder: number }>) => {
const { id, routingOrder } = action.payload;
const recipient = state.recipients.find((r) => r.id === id || r.email === id);
if (recipient) {
recipient.routingOrder = routingOrder;
}
},
updateRecipientIds: (state, action: PayloadAction<Recipient[]>) => {
for (const recObj of state.recipients) {
for (const recObj2 of action.payload) {
recObj.id = recObj2.id;
}
}
},
resetSelRecipient: () => initialState
},
extraReducers: (builder) => {
builder
.addCase(fetchRecipients.pending, () => { })
.addCase(fetchRecipients.fulfilled, (state, action: PayloadAction<Recipient[]>) => {
const assignedRecipients = action.payload.map((recipient, index) => ({
...recipient,
color: colors[index],
}));
state.recipients = assignedRecipients;
})
.addCase(fetchRecipients.rejected, (state, action) => {
console.error("Failed to fetch recipients:", action.payload);
toast.error("Failed to fetch recipients", {
position: "bottom-right",
autoClose: 5000,
theme: "light",
});
})
.addCase(addRecipientAsync.pending, () => { })
.addCase(addRecipientAsync.fulfilled, (state, action: PayloadAction<Recipient[]>) => {
state.recipients = action.payload.map((recipient, index) => ({
...recipient,
color: colors[index % colors.length],
}));
})
.addCase(addRecipientAsync.rejected, (state, action) => {
console.error("Failed to add recipients:", action.payload);
toast.error("Failed to add recipients", {
position: "bottom-right",
autoClose: 5000,
theme: "light",
});
})
.addCase(removeRecipientAsync.pending, () => { })
.addCase(removeRecipientAsync.fulfilled, (state, action: PayloadAction<string | number>) => {
state.recipients = state.recipients.filter(
(recipient) => recipient.id !== action.payload && recipient.email !== action.payload
);
})
.addCase(removeRecipientAsync.rejected, (state, action) => {
console.error("Failed to delete recipient:", action.payload);
toast.error("Failed to delete recipient", {
position: "bottom-right",
autoClose: 5000,
theme: "light",
});
});
}
});
export const {
addRecipient,
setSelectedRecipients,
toggleToTemplates,
removeSelectedRecipient,
setSigningOrder,
addColorsToRecipient,
updateRecipientIds,
resetSelRecipient,
updateRecipientOrder,
resetRecipients
} = selectedRecipientsSlice.actions;
export default selectedRecipientsSlice.reducer;