Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions src/actions/speaker-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const UPDATE_SPEAKER = "UPDATE_SPEAKER";
export const SPEAKER_UPDATED = "SPEAKER_UPDATED";
export const SPEAKER_ADDED = "SPEAKER_ADDED";
export const PIC_ATTACHED = "PIC_ATTACHED";
export const PIC_DELETED = "PIC_DELETED";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 8 --glob '*.js' \
  '\bPIC_DELETED\b|deleteProfilePic|deleteBigPic|currentSpeakerState|big_pic' .

Repository: fntechgit/summit-admin

Length of output: 21131


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- speaker reducer ---'
cat -n src/reducers/speakers/speaker-reducer.js | sed -n '1,210p'

echo '--- action helpers and speaker refresh flow ---'
rg -n -C 10 --glob '*.js' \
  'function deleteRequest|const deleteRequest|export const deleteRequest|deleteRequest\s*=|function getSpeaker|export const getSpeaker|RECEIVE_SPEAKER|PIC_DELETED' src

Repository: fntechgit/summit-admin

Length of output: 42974


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- request helper imports ---'
cat -n src/actions/speaker-actions.js | sed -n '1,50p'

echo '--- update request helper definition and tests ---'
rg -n -C 12 --glob '*.js' \
  'UPDATE_SPEAKER|updateRequest|createAction\(SPEAKER_UPDATED\)|createAction\(UPDATE_SPEAKER\)' src

Repository: fntechgit/summit-admin

Length of output: 12288


Handle PIC_DELETED in speakerReducer.

The reducer ignores PIC_DELETED, so it cannot clear either pic or big_pic. Add photo-type metadata and clear the matching field, or refresh the speaker after deletion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/actions/speaker-actions.js` at line 64, Update speakerReducer to handle
the PIC_DELETED action by using its photo-type metadata to clear the
corresponding pic or big_pic field, or refresh the speaker state after deletion.
Preserve the existing state shape and ensure unrelated photo fields remain
unchanged.

export const BIG_PIC_ATTACHED = "BIG_PIC_ATTACHED";
export const MERGE_SPEAKERS = "MERGE_SPEAKERS";
export const SPEAKER_MERGED = "SPEAKER_MERGED";
Expand Down Expand Up @@ -141,6 +142,18 @@ const uploadProfilePic = (entity, file) => async (dispatch) => {
});
};

const deleteProfilePic = (speakerId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

return deleteRequest(
null,
createAction(PIC_DELETED),
`${window.API_BASE_URL}/api/v1/speakers/${speakerId}/photo?access_token=${accessToken}`,
null,
authErrorHandler
)({})(dispatch);
};

const uploadBigPic = (entity, file) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

Expand All @@ -157,6 +170,18 @@ const uploadBigPic = (entity, file) => async (dispatch) => {
});
};

const deleteBigPic = (speakerId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

return deleteRequest(
null,
createAction(PIC_DELETED),
`${window.API_BASE_URL}/api/v1/speakers/${speakerId}/big-photo?access_token=${accessToken}`,
null,
authErrorHandler
)({})(dispatch);
};

export const initSpeakersList = () => async (dispatch) => {
dispatch(createAction(INIT_SPEAKERS_LIST_PARAMS)());
};
Expand Down Expand Up @@ -343,7 +368,12 @@ export const resetSpeakerForm = () => (dispatch) => {
dispatch(createAction(RESET_SPEAKER_FORM)({}));
};

export const saveSpeaker = (entity) => async (dispatch) => {
export const saveSpeaker = (entity) => async (dispatch, getState) => {
const { currentSpeakerState } = getState();
const { entity: prevSpeaker } = currentSpeakerState;
const removeProfilePic = prevSpeaker?.pic && !entity.pic;
const removeBigPic = prevSpeaker?.big_pic && !entity.big_pic;

const accessToken = await getAccessTokenSafely();

dispatch(startLoading());
Expand All @@ -358,7 +388,13 @@ export const saveSpeaker = (entity) => async (dispatch) => {
normalizedEntity,
authErrorHandler,
entity
)({})(dispatch).then(() => {
)({})(dispatch).then(async () => {
if (removeProfilePic) {
await dispatch(deleteProfilePic(entity.id));
}
if (removeBigPic) {
await dispatch(deleteBigPic(entity.id));
}
Comment on lines +391 to +397

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Return the update and deletion promise chain.

saveSpeaker resolves after it schedules putRequest. It does not wait for the update or either deletion. A caller that awaits dispatch(saveSpeaker(entity)) can continue before the profile photo deletion completes.

Proposed fix
-    putRequest(
+    return putRequest(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/actions/speaker-actions.js` around lines 391 - 397, Update saveSpeaker’s
promise chain around the dispatch callback so it returns the update request and
each conditional deleteProfilePic/deleteBigPic dispatch promise, ensuring
dispatch(saveSpeaker(entity)) remains pending until all requested operations
complete. Preserve the existing conditional deletion behavior and sequencing.

dispatch(showSuccessMessage(T.translate("edit_speaker.speaker_saved")));
});
} else {
Expand Down
Loading