Unify the web UI on shared controls and let pipeline columns be managed on the board.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,11 +29,28 @@ import type {
|
||||
PipelineBoardDto,
|
||||
} from '@mento/shared';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
embedded?: boolean;
|
||||
entityId?: string;
|
||||
initialPersonId?: string;
|
||||
initialType?: ActivityType;
|
||||
initialTitle?: string;
|
||||
}>(),
|
||||
{ embedded: false },
|
||||
);
|
||||
const emit = defineEmits<{ saved: []; cancel: [] }>();
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
const id = computed(() => (typeof route.params.id === 'string' ? route.params.id : ''));
|
||||
const isNew = computed(() => route.name === 'activity-new');
|
||||
const id = computed(() => {
|
||||
if (props.embedded) return props.entityId ?? '';
|
||||
return typeof route.params.id === 'string' ? route.params.id : '';
|
||||
});
|
||||
const isNew = computed(() =>
|
||||
props.embedded ? !props.entityId : route.name === 'activity-new',
|
||||
);
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
@@ -190,18 +207,21 @@ async function load() {
|
||||
isDone.value = data.status === 'done';
|
||||
} else {
|
||||
resetForm();
|
||||
if (typeof route.query.personId === 'string' && route.query.personId) {
|
||||
personId.value = route.query.personId;
|
||||
}
|
||||
const incomingPerson =
|
||||
props.initialPersonId ||
|
||||
(typeof route.query.personId === 'string' ? route.query.personId : '');
|
||||
if (incomingPerson) personId.value = incomingPerson;
|
||||
const incomingType = props.initialType || route.query.type;
|
||||
if (
|
||||
typeof route.query.type === 'string' &&
|
||||
typeOptions.some((o) => o.value === route.query.type)
|
||||
typeof incomingType === 'string' &&
|
||||
typeOptions.some((o) => o.value === incomingType)
|
||||
) {
|
||||
type.value = route.query.type as ActivityType;
|
||||
}
|
||||
if (typeof route.query.title === 'string' && route.query.title) {
|
||||
title.value = route.query.title;
|
||||
type.value = incomingType as ActivityType;
|
||||
}
|
||||
const incomingTitle =
|
||||
props.initialTitle ||
|
||||
(typeof route.query.title === 'string' ? route.query.title : '');
|
||||
if (incomingTitle) title.value = incomingTitle;
|
||||
if (typeof route.query.dueAt === 'string' && route.query.dueAt) {
|
||||
splitDue(new Date(route.query.dueAt).toISOString());
|
||||
}
|
||||
@@ -271,6 +291,10 @@ async function submit(next: 'detail' | 'new' = 'detail') {
|
||||
status: isDone.value ? 'done' : 'open',
|
||||
});
|
||||
}
|
||||
if (props.embedded) {
|
||||
emit('saved');
|
||||
return;
|
||||
}
|
||||
if (next === 'new') {
|
||||
if (!isNew.value) {
|
||||
await router.push({ name: 'activity-new' });
|
||||
@@ -299,6 +323,10 @@ function bumpDuration(delta: number) {
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
if (props.embedded) {
|
||||
emit('cancel');
|
||||
return;
|
||||
}
|
||||
if (!isNew.value && id.value) {
|
||||
void router.push({ name: 'activity-detail', params: { id: id.value } });
|
||||
return;
|
||||
@@ -310,8 +338,14 @@ watch([id, isNew], () => void load(), { immediate: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="page" @click="typeOpen = assigneeOpen = personOpen = false">
|
||||
<header class="desktop-head">
|
||||
<section class="page" :class="{ embedded }" @click="typeOpen = assigneeOpen = personOpen = false">
|
||||
<div v-if="embedded" class="embed-actions">
|
||||
<button class="btn primary" type="button" :disabled="saving" @click="submit('detail')">
|
||||
{{ saving ? 'در حال ذخیره…' : 'ذخیره فعالیت' }}
|
||||
</button>
|
||||
<button class="btn cancel" type="button" :disabled="saving" @click="cancel">انصراف</button>
|
||||
</div>
|
||||
<header v-if="!embedded" class="desktop-head">
|
||||
<p class="crumb">
|
||||
<RouterLink :to="{ name: 'activities' }">فعالیتها</RouterLink>
|
||||
<span>‹</span>
|
||||
@@ -333,7 +367,7 @@ watch([id, isNew], () => void load(), { immediate: true });
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<header class="mobile-head">
|
||||
<header v-if="!embedded" class="mobile-head">
|
||||
<button class="icon-btn" type="button" aria-label="ذخیره" :disabled="saving" @click="submit('detail')">
|
||||
<UiIcon name="check-plain" :size="22" />
|
||||
</button>
|
||||
@@ -579,7 +613,7 @@ watch([id, isNew], () => void load(), { immediate: true });
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<footer class="mobile-save">
|
||||
<footer v-if="!embedded" class="mobile-save">
|
||||
<button class="btn primary" type="button" :disabled="saving || loading" @click="submit('detail')">
|
||||
{{ saving ? 'در حال ذخیره…' : 'ذخیره فعالیت' }}
|
||||
</button>
|
||||
@@ -594,6 +628,16 @@ watch([id, isNew], () => void load(), { immediate: true });
|
||||
padding-bottom: 5.5rem;
|
||||
}
|
||||
|
||||
.page.embedded {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.embed-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.desktop-head {
|
||||
display: none;
|
||||
justify-content: space-between;
|
||||
|
||||
Reference in New Issue
Block a user