import {createSlice, createAsyncThunk} from "@reduxjs/toolkit"; import FirebaseQuery from "../../firebase/firebaseQuery"; import { arrayRemove, arrayUnion, DocumentData } from "firebase/firestore"; import { deleteStorageItem, uploadFiles } from "../../firebase/writeDatabase"; type InitialLogsState = { status: string, values: { [key: string]: DocumentData } } const initialState: InitialLogsState = { status: "", values: {} }; export const fetchLogs = createAsyncThunk( "logs/fetchLogs", async ({placementId, selectedDate}: {placementId: string, selectedDate: string}, { rejectWithValue }) => { const firebaseQuery = new FirebaseQuery(); try { const data = await firebaseQuery.getDocData(["logs", `${placementId}-${selectedDate}`]) return {"data": data, "selectedDate": selectedDate} } catch (error) { return {"data": {}, "selectedDate": selectedDate} } } ); export const editLog = createAsyncThunk( "logs/editLog", async ({value, selectedDate, userType, placementId}: {value: any[] | {[key: string]: unknown}, selectedDate: string, userType: string, placementId: string}, { rejectWithValue }) => { const firebaseQuery = new FirebaseQuery(); try { const empty = (Array.isArray(value) && value.length === 0) || (Object.entries(Object.values(value)[0] as { [key: string]: unknown }) .filter(([k, v]) => (![`${userType}Uid`, "completed"].includes(k)) && v) .length === 0); const updatedValue = empty ? null : Array.isArray(value) ? value : Object.values(value)[0]; await firebaseQuery.set( ["logs", `${placementId}-${selectedDate}`], { [userType]: updatedValue }, true ); await firebaseQuery.update( ["placements", placementId], { [userType + "Logs"]: empty ? arrayRemove(selectedDate) : arrayUnion(selectedDate) } ); return {"data": updatedValue, "selectedDate": selectedDate, "userType": userType} } catch (error) { return rejectWithValue(error); } } ) export const addLogFile = createAsyncThunk( "logs/addLogFile", async ({files, userType, selectedDate, placementId}: {files: {file: FileList}, userType: string, selectedDate: string, placementId: string}, { rejectWithValue }) => { const firebaseQuery = new FirebaseQuery(); try { const newFileNames = Array.from(files.file).map(file => file.name); await uploadFiles( Array.from(files.file), ["placements", placementId, "log", `${userType}_files`, selectedDate] ); await firebaseQuery.set( ["logs", `${placementId}-${selectedDate}`], { [`${userType}_files`]: arrayUnion(...newFileNames) }, true ); return {"data": newFileNames, "userType": userType, "selectedDate": selectedDate} } catch (error) { return rejectWithValue(error); } } ) export const deleteLogFile = createAsyncThunk( "logs/deleteLogFile", async ({openFile, userType, selectedDate, placementId}: {openFile: {name: string, url: string}, userType: string, selectedDate: string, placementId: string}, { rejectWithValue }) => { const firebaseQuery = new FirebaseQuery(); try { await deleteStorageItem(`placements/${placementId}/log/${userType}_files/${selectedDate}/${openFile.name}`); await firebaseQuery.set( ["logs", `${placementId}-${selectedDate}`], { [`${userType}_files`]: arrayRemove(openFile.name) }, true ); return {"openFile": openFile, "userType": userType, "selectedDate": selectedDate} } catch (error) { return rejectWithValue(error); } } ) export const logsSlice = createSlice({ name: "logs", initialState, reducers: {}, extraReducers(builder){ builder .addCase(fetchLogs.pending, (state) => { state.status = "loading" }) .addCase(fetchLogs.fulfilled, (state, action) => { state.status = "success"; const {data, selectedDate} = action.payload state.values = {...state.values, [selectedDate]: data} }) .addCase(fetchLogs.rejected, (state) => { state.status = "rejected" }) builder .addCase(editLog.pending, (state) => { state.status = "loading" }) .addCase(editLog.fulfilled, (state, action) => { state.status = "success"; const {data, selectedDate, userType} = action.payload const updatedLog = { ...state.values, [userType]: data } state.values = {...state.values, [selectedDate]: updatedLog} }) .addCase(editLog.rejected, (state) => { state.status = "rejected" }) builder .addCase(addLogFile.pending, (state) => { state.status = "loading" }) .addCase(addLogFile.fulfilled, (state, action) => { state.status = "success"; const {data, selectedDate, userType} = action.payload; const currentFiles = state.values[selectedDate]?.[`${userType}_files`] || []; const updatedFiles = [...currentFiles, ...data]; state.values = { ...state.values, [selectedDate]: { ...state.values[selectedDate], [`${userType}_files`]: updatedFiles } }; }) .addCase(addLogFile.rejected, (state) => { state.status = "rejected" }) builder .addCase(deleteLogFile.pending, (state) => { state.status = "loading" }) .addCase(deleteLogFile.fulfilled, (state, action) => { state.status = "success"; const {openFile, selectedDate, userType} = action.payload; const currentLog = state.values[selectedDate] || {} const updatedFiles = currentLog[`${userType}_files`]?.filter((file: string) => file !== openFile.name) || []; state.values = { ...state.values, [selectedDate]: { ...currentLog, [`${userType}_files`]: updatedFiles } }; }) .addCase(deleteLogFile.rejected, (state) => { state.status = "rejected" }) } }) export default logsSlice.reducer;