diff --git a/apps/platform/src/journey/JourneyController.ts b/apps/platform/src/journey/JourneyController.ts index 9f14e884..56cc26c2 100644 --- a/apps/platform/src/journey/JourneyController.ts +++ b/apps/platform/src/journey/JourneyController.ts @@ -211,15 +211,15 @@ router.get('/:journeyId/steps/:stepId/users', async ctx => { ctx.body = await pagedUsersByStep(step.id, params) }) -router.delete('/:journeyId/users/:userId', async ctx => { +router.delete('/:journeyId/users/:userId/step/:stepId', async ctx => { const user = await getUserFromContext(ctx) if (!user) return ctx.throw(404) const results = await JourneyUserStep.update( - q => q.where('user_id', user.id) - .whereNull('entrance_id') + q => q.where('id', parseInt(ctx.params.stepId)) + .where('user_id', user.id) .whereNull('ended_at') .where('journey_id', ctx.state.journey!.id), - { ended_at: new Date() }, + { ended_at: new Date(), delay_until: null, type: 'completed' }, ) ctx.body = { exits: results } }) diff --git a/apps/platform/src/journey/JourneyRepository.ts b/apps/platform/src/journey/JourneyRepository.ts index 0523b754..dfe0c458 100644 --- a/apps/platform/src/journey/JourneyRepository.ts +++ b/apps/platform/src/journey/JourneyRepository.ts @@ -334,7 +334,7 @@ export const pagedUsersByStep = async (stepId: number, params: PageParams) => { export const getEntranceLog = async (entranceId: number) => { const userSteps = await JourneyUserStep.all(q => q - .where(function() { + .where(function () { return this.where('id', entranceId).orWhere('entrance_id', entranceId) }) .orderBy('id', 'asc'), @@ -364,7 +364,7 @@ export const exitUserFromJourney = async (userId: number, entranceId: number, jo .where('id', entranceId) .whereNull('ended_at') .where('journey_id', journeyId), - { ended_at: new Date() }, + { ended_at: new Date(), delay_until: null, type: 'completed' }, ) } diff --git a/apps/platform/src/journey/JourneyUserStep.ts b/apps/platform/src/journey/JourneyUserStep.ts index edb66ba4..d946f2ef 100644 --- a/apps/platform/src/journey/JourneyUserStep.ts +++ b/apps/platform/src/journey/JourneyUserStep.ts @@ -6,7 +6,7 @@ export default class JourneyUserStep extends Model { type!: string journey_id!: number step_id!: number - delay_until?: Date + delay_until?: Date | null entrance_id?: number ended_at?: Date data?: Record | null diff --git a/apps/ui/public/locales/en.json b/apps/ui/public/locales/en.json index 0eadaa99..194c6686 100644 --- a/apps/ui/public/locales/en.json +++ b/apps/ui/public/locales/en.json @@ -333,6 +333,7 @@ "setup_integration_no_providers": "There are no providers configured for this channel. Please add a provider to continue.", "sign_out": "Sign Out", "skip_delay": "Skip Delay", + "remove_from_journey": "Remove from journey", "sms_opt_out_message": "SMS Opt Out Message", "sms_opt_out_message_subtitle": "Instructions on how to opt out of SMS that will be appended to every text.", "sms_help_message": "SMS Help Message", diff --git a/apps/ui/src/api.ts b/apps/ui/src/api.ts index 76d135a6..c36165db 100644 --- a/apps/ui/src/api.ts +++ b/apps/ui/src/api.ts @@ -221,6 +221,9 @@ const api = { skipDelay: async (projectId: number | string, journeyId: number | string, userId: number | string, stepId: number | string) => await client .post(`${projectUrl(projectId)}/journeys/${journeyId}/users/${userId}/steps/${stepId}/resume`) .then(r => r.data), + removeFromJourney: async (projectId: number | string, journeyId: number | string, userId: number | string, stepId: number | string) => await client + .delete(`${projectUrl(projectId)}/journeys/${journeyId}/users/${userId}/step/${stepId}`) + .then(r => r.data), }, }, diff --git a/apps/ui/src/views/journey/JourneyStepUsers.tsx b/apps/ui/src/views/journey/JourneyStepUsers.tsx index d44963b9..9fb5efb2 100644 --- a/apps/ui/src/views/journey/JourneyStepUsers.tsx +++ b/apps/ui/src/views/journey/JourneyStepUsers.tsx @@ -9,7 +9,7 @@ import { UserLookup } from '../users/UserLookup' import { typeVariants } from './EntranceDetails' import { ModalProps } from '../../ui/Modal' import { JourneyUserStep, User } from '../../types' -import { EditIcon } from '../../ui/icons' +import { EditIcon, TrashIcon } from '../../ui/icons' import { DataTableCol } from '../../ui/DataTable' interface StepUsersProps extends Omit { @@ -28,13 +28,21 @@ export function JourneyStepUsers({ open, onClose, stepType, stepId }: StepUsersP ? [{ key: 'options', title: t('options'), - cell: ({ item: { id, user } }) => { - if (user) { + cell: ({ item: { id, user, type } }) => { + if (user && type !== 'completed') { return ( await handleSkipDelay(id, user)}> {t('skip_delay')} + + + ) } @@ -59,6 +67,11 @@ export function JourneyStepUsers({ open, onClose, stepType, stepId }: StepUsersP await state.reload() } + const handleRemoveFromJourney = async (stepId: number, user: User) => { + await api.journeys.users.removeFromJourney(projectId, journeyId, user.id, stepId) + await state.reload() + } + return <>