Skip to content

Commit

Permalink
feat(prompts): carousel prompt element (V4-1406)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukashroch committed Feb 13, 2025
1 parent ce83363 commit 6e6fef5
Show file tree
Hide file tree
Showing 24 changed files with 513 additions and 151 deletions.
11 changes: 10 additions & 1 deletion apps/admin/src/components/prompts/custom/info-prompt.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
@update:model-value="update('video', $event)"
/>
</v-col>
<v-col :cols="12">
<carousel
:model-value="carousel"
@update:model-value="update('carousel', $event)"
/>
</v-col>
</v-row>
</v-tabs-window-item>
</template>
Expand All @@ -29,7 +35,7 @@ import type { PropType } from 'vue';
import { ytVideoDefaults } from '@intake24/common/prompts';
import type { Prompts } from '@intake24/common/prompts';
import { useI18n } from '@intake24/i18n';
import { useBasePrompt, YoutubeVideo } from '../partials';
import { Carousel, useBasePrompt, YoutubeVideo } from '../partials';
defineOptions({
name: 'InfoPrompt',
Expand All @@ -38,6 +44,9 @@ defineOptions({
});
const props = defineProps({
carousel: {
type: Object as PropType<Prompts['info-prompt']['carousel']>,
},
video: {
type: [Boolean, Object] as PropType<Prompts['info-prompt']['video']>,
},
Expand Down
197 changes: 197 additions & 0 deletions apps/admin/src/components/prompts/partials/carousel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<template>
<v-card border flat>
<v-toolbar color="grey-lighten-4">
<v-icon end icon="fas fa-sliders" />
<v-toolbar-title>
{{ $t('survey-schemes.prompts.carousel.title') }}
</v-toolbar-title>
<v-spacer />
<v-toolbar-items>
<v-switch
v-model="toggle"
class="mx-3"
hide-details="auto"
@update:model-value="changeToggle"
/>
</v-toolbar-items>
</v-toolbar>
<v-container>
<v-row v-if="carousel">
<v-col cols="12" md="6">
<v-select
v-model="carousel.variant"
hide-details="auto"
:items="variants"
:label="$t('survey-schemes.theme.variants._')"
variant="outlined"
/>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="carousel.color"
hide-details="auto"
:items="colors"
:label="$t('survey-schemes.theme.colors._')"
variant="outlined"
>
<template #item="{ item, props }">
<v-list-item v-bind="props" :title="item.raw.title">
<template #prepend>
<span
class="mr-2 pa-4 rounded-circle"
:style="{ backgroundColor: item.raw.color }"
/>
</template>
</v-list-item>
</template>
<template #selection="{ item }">
<span
class="mr-2 pa-2 rounded-circle"
:style="{ backgroundColor: item.raw.color }"
/>
{{ item.raw.title }}
</template>
</v-select>
</v-col>
<v-col cols="12" md="6">
<v-switch
v-model="carousel.required"
hide-details="auto"
:label="$t('survey-schemes.prompts.carousel.required')"
/>
</v-col>
</v-row>
<div v-if="carousel" class="mt-4">
<div class="text-h5 mb-4">
{{ $t('survey-schemes.prompts.carousel.slides.title') }}
</div>
<div class="d-flex flex-row ga-2">
<div>
<v-btn class="mb-4" color="primary" @click="add">
<v-icon icon="$add" start />
{{ $t('survey-schemes.prompts.carousel.slides.add') }}
</v-btn>
<v-tabs v-model="selectedSlide" direction="vertical">
<vue-draggable
v-model="carousel.slides"
:animation="300"
handle=".drag-and-drop__handle"
>
<v-tab v-for="(slide, idx) in carousel.slides" :key="slide.id" class="d-flex ga-3" :value="slide.id">
<v-icon class="drag-and-drop__handle" icon="$handle" start />
{{ $t('survey-schemes.prompts.carousel.slides._') }} #{{ idx + 1 }}
</v-tab>
</vue-draggable>
</v-tabs>
</div>
<v-tabs-window v-model="selectedSlide" class="flex-grow-1">
<v-tabs-window-item v-for="(slide, idx) in carousel.slides" :key="slide.id" :value="slide.id">
<v-card border flat>
<v-card-title>
<v-icon icon="fas fa-location-arrow" start />
{{ $t('survey-schemes.prompts.carousel.slides._') }} #{{ idx + 1 }}
</v-card-title>
<v-container>
<v-row>
<v-col cols="12">
<v-text-field
v-model="slide.image.desktop"
append-inner-icon="$desktop"
hide-details="auto"
:label="`${$t('survey-schemes.prompts.carousel.slides.image')} (${$t('survey-schemes.theme.layouts.desktop')})`"
prepend-inner-icon="fas fa-image"
variant="outlined"
/>
</v-col>
<v-col cols="12">
<v-text-field
v-model="slide.image.mobile"
append-inner-icon="$mobile"
hide-details="auto"
:label="`${$t('survey-schemes.prompts.carousel.slides.image')} (${$t('survey-schemes.theme.layouts.mobile')})`"
prepend-inner-icon="fas fa-image"
variant="outlined"
/>
</v-col>
<v-col cols="12">
<language-selector
v-model="slide.text"
border
:label="$t('survey-schemes.prompts.carousel.slides.text')"
:required="true"
>
<template v-for="lang in Object.keys(slide.text)" :key="lang" #[`lang.${lang}`]>
<html-editor v-model="slide.text[lang]" />
</template>
</language-selector>
</v-col>
</v-row>
</v-container>
<v-card-actions>
<v-spacer />
<v-btn class="font-weight-bold" color="error" variant="text" @click="remove(idx)">
<v-icon icon="$delete" start />
{{ $t('survey-schemes.prompts.carousel.slides.remove') }}
</v-btn>
</v-card-actions>
</v-card>
</v-tabs-window-item>
</v-tabs-window>
</div>
</div>
</v-container>
</v-card>
</template>

<script lang="ts" setup>
import type { PropType } from 'vue';
import { useVModel } from '@vueuse/core';
import { ref } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';
import { HtmlEditor } from '@intake24/admin/components/editors';
import { LanguageSelector } from '@intake24/admin/components/forms';
import { useSelects } from '@intake24/admin/composables';
import { carouselDefaults } from '@intake24/common/prompts';
import type { Carousel } from '@intake24/common/prompts';
import { randomString } from '@intake24/common/util';
defineOptions({ name: 'Carousel' });
const props = defineProps({
modelValue: {
type: Object as PropType<Carousel>,
},
});
const emit = defineEmits(['update:modelValue']);
const { colors, variants } = useSelects();
const carousel = useVModel(props, 'modelValue', emit, { passive: true, deep: true });
const selectedSlide = ref(carousel.value?.slides.length ? carousel.value.slides[0].id : undefined);
const toggle = ref(!!carousel.value);
function changeToggle(enable: boolean | null) {
carousel.value = enable ? carouselDefaults : undefined;
};
function add() {
const id = randomString(6);
carousel.value?.slides.push({
id,
text: { en: 'Carousel slide' },
image: { desktop: '', mobile: '' },
});
selectedSlide.value = id;
};
function remove(index: number) {
carousel.value?.slides.splice(index, 1);
selectedSlide.value = carousel.value?.slides.at(-1)?.id ?? undefined;
};
</script>

<style lang="scss" scoped></style>
1 change: 1 addition & 0 deletions apps/admin/src/components/prompts/partials/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as BarcodeSettings } from './barcode-settings.vue';
export { default as basePrompt } from './base-prompt';
export { default as Carousel } from './carousel.vue';
export { default as CounterSettings } from './counter-settings.vue';
export { default as ExternalSourceSettings } from './external-source-settings.vue';
export { default as FoodBrowserSettings } from './food-browser-settings.vue';
Expand Down
24 changes: 9 additions & 15 deletions apps/admin/src/components/prompts/partials/prompt-actions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@
@end="update"
>
<v-tab v-for="(action, idx) in currentActions.items" :key="action.id" class="d-flex ga-3" :value="action.id">
<v-icon class="drag-and-drop__handle">
$handle
</v-icon>
<v-icon class="drag-and-drop__handle" icon="$handle" start />
{{ $t(`survey-schemes.actions.types.${action.type}`) }}({{ idx + 1 }})
</v-tab>
</vue-draggable>
Expand Down Expand Up @@ -66,7 +64,7 @@
v-model="action.layout"
hide-details="auto"
:items="layouts"
:label="$t('survey-schemes.actions.layouts._')"
:label="$t('survey-schemes.theme.layouts._')"
multiple
variant="outlined"
/>
Expand All @@ -75,8 +73,8 @@
<v-select
v-model="action.variant"
hide-details="auto"
:items="actionVariants"
:label="$t('survey-schemes.actions.variants._')"
:items="variants"
:label="$t('survey-schemes.theme.variants._')"
variant="outlined"
/>
</v-col>
Expand All @@ -85,7 +83,7 @@
v-model="action.color"
hide-details="auto"
:items="colors"
:label="$t('survey-schemes.actions.color')"
:label="$t('survey-schemes.theme.colors._')"
variant="outlined"
>
<template #item="{ item, props }">
Expand Down Expand Up @@ -201,7 +199,7 @@ const props = defineProps({
const emit = defineEmits(['update:actions']);
const { actions: availableActions, actionVariants, colors, layouts } = useSelects();
const { actions: availableActions, colors, layouts, variants } = useSelects();
const currentActions = ref(props.actions ? { ...props.actions, items: withIdList(props.actions.items) } : undefined);
const selectedAction = ref(currentActions.value?.items.length ? currentActions.value.items[0].id : undefined);
Expand All @@ -217,13 +215,8 @@ const outputActions = computed(() => {
};
});
function changeToggle(enable: boolean) {
if (!enable) {
currentActions.value = undefined;
return;
}
currentActions.value = { both: false, items: [] };
function changeToggle(enable: boolean | null) {
currentActions.value = enable ? { both: false, items: [] } : undefined;
};
function add() {
Expand All @@ -235,6 +228,7 @@ function add() {
function remove(index: number) {
currentActions.value?.items.splice(index, 1);
selectedAction.value = currentActions.value?.items.at(-1)?.id ?? undefined;
};
function update() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@
<v-chip v-if="condition.orPrevious" class="font-weight-medium position-absolute" style="top: -1.5em;">
OR
</v-chip>
<v-icon class="drag-and-drop__handle" start>
$handle
</v-icon>
<v-icon class="drag-and-drop__handle " icon="$handle" start />
{{ $t(`survey-schemes.conditions.property.${condition.property.id}`) }}
</v-tab>
</vue-draggable>
Expand Down Expand Up @@ -181,6 +179,8 @@ export default defineComponent({
currentConditions.value.splice(index, 1);
if (currentConditions.value.length > 0)
currentConditions.value[0].orPrevious = false;
selectedCondition.value = currentConditions.value?.at(-1)?.id ?? undefined;
};
const update = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
v-for="key in keys"
:key="key"
:items="options"
:label="$t(`survey-schemes.actions.layouts.${key}`)"
:label="$t(`survey-schemes.theme.layouts.${key}`)"
:model-value="review[key]"
:prepend-inner-icon="`$${key}`"
variant="outlined"
Expand Down
18 changes: 9 additions & 9 deletions apps/admin/src/composables/use-selects.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import orderBy from 'lodash/orderBy';

import { actionTypes as actionTypeRefs, actionVariants as actionVariantRefs, conditionOpCodes, promptLayouts } from '@intake24/common/prompts';
import { actionTypes as actionTypeRefs, conditionOpCodes, layoutTypes } from '@intake24/common/prompts';
import type { ConditionOpCode } from '@intake24/common/prompts';
import { recordVisibilities } from '@intake24/common/security';
import { recallFlows as recallFlowRefs, schemeTypes as schemeTypeRefs } from '@intake24/common/surveys';
import { colors as themeColors } from '@intake24/common/theme';
import { colors as themeColors, variants as themeVariants } from '@intake24/common/theme';
import { textDirections as textDirectionRefs } from '@intake24/common/types';
import { useI18n } from '@intake24/i18n';

Expand All @@ -18,9 +18,9 @@ export function useSelects() {
title: t(`survey-schemes.actions.types.${value}`),
}));

const actionVariants = actionVariantRefs.map(value => ({
const variants = themeVariants.map(value => ({
value,
title: t(`survey-schemes.actions.variants.${value}`),
title: t(`survey-schemes.theme.variants.${value}`),
}));

const colors = Object.entries(themeColors).map(([key, color]) => ({
Expand All @@ -43,9 +43,9 @@ export function useSelects() {
'title',
);

const layouts = promptLayouts.map(value => ({
const layouts = layoutTypes.map(value => ({
value,
title: t(`survey-schemes.actions.layouts.${value}`),
title: t(`survey-schemes.theme.layouts.${value}`),
}));

const orientations = ['column', 'row'].map(value => ({
Expand Down Expand Up @@ -77,15 +77,15 @@ export function useSelects() {

return {
actions,
actionVariants,
colors,
conditionOps,
flags,
layouts,
orientations,
textDirections,
visibilities,
recallFlows,
schemeTypes,
textDirections,
variants,
visibilities,
};
}
Loading

0 comments on commit 6e6fef5

Please sign in to comment.