BaaS_Driver_Android_App/store/paymentSlice.ts

153 lines
4.2 KiB
TypeScript

import { BASE_URL } from "@/constants/config";
import api from "@/services/axiosClient";
import { toCamel } from "@/utils/Payments";
import { createSlice, PayloadAction, createAsyncThunk } from "@reduxjs/toolkit";
import { AxiosError } from "axios";
type LastEmiStatus = "pending" | "completed";
export interface MyPlan {
noOfEmi: number | null;
totalAmount: number | null;
downPayment: number | null;
emiAmount: number | null;
totalEmi: number | null;
installmentPaid: number | null;
currentAmount: number | null;
}
export interface EmiDetails {
dueAmount: number | null;
totalAmountPaidInCurrentCycle: number | null;
dueDate: string | null;
status: LastEmiStatus | null;
advanceBalance: number | null;
pendingCycles: number | null;
totalPendingInstallments: number | null;
myPlan: MyPlan;
}
type LoadingState = "idle" | "pending" | "succeeded" | "failed";
export interface EmiDetailsState {
item?: EmiDetails;
loading: LoadingState;
error?: string;
lastFetchedAt?: number;
}
const initialState: EmiDetailsState = {
item: undefined,
loading: "idle",
error: undefined,
lastFetchedAt: undefined,
};
export interface MyPlanApi {
no_of_emi: number | null;
total_amount: number | null;
down_payment: number | null;
emi_amount: number | null;
total_emi: number | null;
installment_paid: number | null;
current_amount: number | null;
}
export interface EmiDetailsApi {
due_amount: number | null;
total_amount_paid_in_current_cycle: number | null;
due_date: string | null;
status: LastEmiStatus | null;
advance_balance: number | null;
pending_cycles: number | null;
total_pending_installments: number | null;
myPlain: MyPlanApi;
}
export interface EmiDetailsResponse {
success: boolean;
data: EmiDetailsApi[];
}
const mapEmiDetailsApiToModel = (apiObj: EmiDetailsApi): EmiDetails => ({
dueAmount: apiObj.due_amount,
totalAmountPaidInCurrentCycle: apiObj.total_amount_paid_in_current_cycle,
dueDate: apiObj.due_date,
status: apiObj.status,
advanceBalance: apiObj.advance_balance,
pendingCycles: apiObj.pending_cycles,
totalPendingInstallments: apiObj.total_pending_installments,
myPlan: {
noOfEmi: apiObj.myPlain.no_of_emi,
totalAmount: apiObj.myPlain.total_amount,
downPayment: apiObj.myPlain.down_payment,
emiAmount: apiObj.myPlain.emi_amount,
totalEmi: apiObj.myPlain.total_emi,
installmentPaid: apiObj.myPlain.installment_paid,
currentAmount: apiObj.myPlain.current_amount,
},
});
export const fetchEmiDetails = createAsyncThunk<
EmiDetails,
void,
{ rejectValue: string }
>("emiDetails/fetch", async (_: void, { rejectWithValue }) => {
try {
const res = await api.get(`${BASE_URL}}/api/v1/emi-details`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
const json = res.data;
const first = json?.data?.[0];
if (!json?.success || !first) {
return rejectWithValue("No EMI details found");
}
return mapEmiDetailsApiToModel(first);
} catch (e: any) {
const err = e as AxiosError<any>;
if (err.code === "ERR_CANCELED") return rejectWithValue("Request aborted");
const msg =
err.response?.data?.message || err.message || "Something went wrong";
return rejectWithValue(msg);
}
});
const emiDetailsSlice = createSlice({
name: "emiDetails",
initialState,
reducers: {
clearEmiDetails(state) {
state.item = undefined;
state.error = undefined;
state.loading = "idle";
state.lastFetchedAt = undefined;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchEmiDetails.pending, (state) => {
state.loading = "pending";
state.error = undefined;
})
.addCase(
fetchEmiDetails.fulfilled,
(state, action: PayloadAction<EmiDetails>) => {
state.loading = "succeeded";
state.item = action.payload;
state.lastFetchedAt = Date.now();
}
)
.addCase(fetchEmiDetails.rejected, (state, action) => {
state.loading = "failed";
state.error = action.payload as string | undefined;
});
},
});
export const { clearEmiDetails } = emiDetailsSlice.actions;
export default emiDetailsSlice.reducer;