feat(workspace): add hidden contacts filter and remove calendar scene swap
This commit is contained in:
@@ -41,6 +41,7 @@ type CalendarView = "day" | "week" | "month" | "year" | "agenda";
|
|||||||
type SortMode = "name" | "lastContact";
|
type SortMode = "name" | "lastContact";
|
||||||
type PeopleLeftMode = "contacts" | "calendar";
|
type PeopleLeftMode = "contacts" | "calendar";
|
||||||
type PeopleSortMode = "name" | "lastContact" | "company" | "country";
|
type PeopleSortMode = "name" | "lastContact" | "company" | "country";
|
||||||
|
type PeopleVisibilityMode = "all" | "hidden";
|
||||||
type DocumentSortMode = "updatedAt" | "title" | "owner";
|
type DocumentSortMode = "updatedAt" | "title" | "owner";
|
||||||
|
|
||||||
type FeedCard = {
|
type FeedCard = {
|
||||||
@@ -2397,7 +2398,6 @@ const calendarZoomOverlay = ref<{ active: boolean } & CalendarRect>({
|
|||||||
});
|
});
|
||||||
const calendarZoomGhost = ref<CalendarZoomGhost | null>(null);
|
const calendarZoomGhost = ref<CalendarZoomGhost | null>(null);
|
||||||
const calendarZoomBusy = ref(false);
|
const calendarZoomBusy = ref(false);
|
||||||
const calendarSceneMasked = ref(false);
|
|
||||||
const calendarCameraState = ref({
|
const calendarCameraState = ref({
|
||||||
active: false,
|
active: false,
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -2412,6 +2412,8 @@ let calendarWheelLockUntil = 0;
|
|||||||
let calendarZoomPrimeTimer: ReturnType<typeof setTimeout> | null = null;
|
let calendarZoomPrimeTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
let calendarZoomPrimeLastAt = 0;
|
let calendarZoomPrimeLastAt = 0;
|
||||||
const CALENDAR_ZOOM_DURATION_MS = 2400;
|
const CALENDAR_ZOOM_DURATION_MS = 2400;
|
||||||
|
const CALENDAR_ZOOM_FOCUS_MS = 1400;
|
||||||
|
const CALENDAR_ZOOM_REVEAL_MS = Math.max(500, CALENDAR_ZOOM_DURATION_MS - CALENDAR_ZOOM_FOCUS_MS);
|
||||||
const CALENDAR_ZOOM_PRIME_STEPS = 2;
|
const CALENDAR_ZOOM_PRIME_STEPS = 2;
|
||||||
const CALENDAR_ZOOM_PRIME_MAX_SCALE = 1.05;
|
const CALENDAR_ZOOM_PRIME_MAX_SCALE = 1.05;
|
||||||
const CALENDAR_ZOOM_PRIME_RESET_MS = 900;
|
const CALENDAR_ZOOM_PRIME_RESET_MS = 900;
|
||||||
@@ -2762,11 +2764,15 @@ function waitCalendarZoomTransition() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function animateCalendarZoomIn(sourceElement: HTMLElement | null, ghost: CalendarZoomGhost, apply: () => void) {
|
async function animateCalendarZoomIn(
|
||||||
|
sourceElement: HTMLElement | null,
|
||||||
|
ghost: CalendarZoomGhost,
|
||||||
|
apply: () => void,
|
||||||
|
resolveRevealTarget?: () => HTMLElement | null,
|
||||||
|
) {
|
||||||
clearCalendarZoomPrime();
|
clearCalendarZoomPrime();
|
||||||
calendarZoomBusy.value = true;
|
calendarZoomBusy.value = true;
|
||||||
clearCalendarZoomOverlay();
|
clearCalendarZoomOverlay();
|
||||||
calendarSceneMasked.value = false;
|
|
||||||
try {
|
try {
|
||||||
calendarZoomGhost.value = ghost;
|
calendarZoomGhost.value = ghost;
|
||||||
const fromRect = getElementRectInScene(sourceElement) ?? fallbackZoomOriginRectInScene();
|
const fromRect = getElementRectInScene(sourceElement) ?? fallbackZoomOriginRectInScene();
|
||||||
@@ -2790,19 +2796,36 @@ async function animateCalendarZoomIn(sourceElement: HTMLElement | null, ghost: C
|
|||||||
left: cameraTarget.left,
|
left: cameraTarget.left,
|
||||||
top: cameraTarget.top,
|
top: cameraTarget.top,
|
||||||
scale: cameraTarget.scale,
|
scale: cameraTarget.scale,
|
||||||
durationMs: CALENDAR_ZOOM_DURATION_MS,
|
durationMs: CALENDAR_ZOOM_FOCUS_MS,
|
||||||
};
|
};
|
||||||
await waitCalendarCameraTransition();
|
await waitCalendarCameraTransition();
|
||||||
// Freeze the filled block frame, then swap level while scene is masked.
|
|
||||||
// This keeps the "zoom into block -> reveal next grid inside" sequence.
|
|
||||||
calendarSceneMasked.value = true;
|
|
||||||
await nextAnimationFrame();
|
|
||||||
apply();
|
apply();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
const revealTargetElement = resolveRevealTarget ? resolveRevealTarget() : sourceElement;
|
||||||
|
const revealTargetRect = getElementRectInScene(revealTargetElement) ?? fallbackZoomOriginRectInScene();
|
||||||
|
const revealTarget = revealTargetRect ? cameraTransformForRect(revealTargetRect) : null;
|
||||||
|
if (revealTarget) {
|
||||||
|
calendarCameraState.value = {
|
||||||
|
active: true,
|
||||||
|
left: revealTarget.left,
|
||||||
|
top: revealTarget.top,
|
||||||
|
scale: revealTarget.scale,
|
||||||
|
durationMs: 0,
|
||||||
|
};
|
||||||
|
await nextTick();
|
||||||
|
await nextAnimationFrame();
|
||||||
|
}
|
||||||
|
calendarCameraState.value = {
|
||||||
|
active: true,
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
scale: 1,
|
||||||
|
durationMs: CALENDAR_ZOOM_REVEAL_MS,
|
||||||
|
};
|
||||||
|
await waitCalendarCameraTransition();
|
||||||
} finally {
|
} finally {
|
||||||
await resetCalendarCamera();
|
await resetCalendarCamera();
|
||||||
calendarZoomGhost.value = null;
|
calendarZoomGhost.value = null;
|
||||||
calendarSceneMasked.value = false;
|
|
||||||
calendarZoomBusy.value = false;
|
calendarZoomBusy.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2813,15 +2836,11 @@ async function animateCalendarZoomOut(apply: () => void, resolveTarget: () => HT
|
|||||||
clearCalendarZoomOverlay();
|
clearCalendarZoomOverlay();
|
||||||
try {
|
try {
|
||||||
calendarZoomGhost.value = zoomGhostForCurrentView();
|
calendarZoomGhost.value = zoomGhostForCurrentView();
|
||||||
calendarSceneMasked.value = true;
|
|
||||||
apply();
|
apply();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
const targetRect = getElementRectInScene(resolveTarget()) ?? fallbackZoomOriginRectInScene();
|
const targetRect = getElementRectInScene(resolveTarget()) ?? fallbackZoomOriginRectInScene();
|
||||||
const cameraStart = targetRect ? cameraTransformForRect(targetRect) : null;
|
const cameraStart = targetRect ? cameraTransformForRect(targetRect) : null;
|
||||||
if (!cameraStart) {
|
if (!cameraStart) return;
|
||||||
calendarSceneMasked.value = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
calendarCameraState.value = {
|
calendarCameraState.value = {
|
||||||
active: true,
|
active: true,
|
||||||
left: cameraStart.left,
|
left: cameraStart.left,
|
||||||
@@ -2832,8 +2851,6 @@ async function animateCalendarZoomOut(apply: () => void, resolveTarget: () => HT
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
await nextAnimationFrame();
|
await nextAnimationFrame();
|
||||||
calendarSceneRef.value?.getBoundingClientRect();
|
calendarSceneRef.value?.getBoundingClientRect();
|
||||||
calendarSceneMasked.value = false;
|
|
||||||
await nextAnimationFrame();
|
|
||||||
calendarCameraState.value = {
|
calendarCameraState.value = {
|
||||||
active: true,
|
active: true,
|
||||||
left: 0,
|
left: 0,
|
||||||
@@ -2845,7 +2862,6 @@ async function animateCalendarZoomOut(apply: () => void, resolveTarget: () => HT
|
|||||||
} finally {
|
} finally {
|
||||||
await resetCalendarCamera();
|
await resetCalendarCamera();
|
||||||
calendarZoomGhost.value = null;
|
calendarZoomGhost.value = null;
|
||||||
calendarSceneMasked.value = false;
|
|
||||||
calendarZoomBusy.value = false;
|
calendarZoomBusy.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2895,7 +2911,7 @@ async function zoomInCalendar(event?: Event) {
|
|||||||
if (maybePrimeWheelZoom(wheelEvent, calendarPrimeMonthToken(monthIndex))) return;
|
if (maybePrimeWheelZoom(wheelEvent, calendarPrimeMonthToken(monthIndex))) return;
|
||||||
await animateCalendarZoomIn(sourceElement, zoomGhostForMonth(monthIndex), () => {
|
await animateCalendarZoomIn(sourceElement, zoomGhostForMonth(monthIndex), () => {
|
||||||
openYearMonth(monthIndex);
|
openYearMonth(monthIndex);
|
||||||
});
|
}, () => queryCalendarElement(`[data-calendar-month-index="${monthIndex}"]`));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2914,6 +2930,9 @@ async function zoomInCalendar(event?: Event) {
|
|||||||
() => {
|
() => {
|
||||||
openWeekView(anchorDayKey);
|
openWeekView(anchorDayKey);
|
||||||
},
|
},
|
||||||
|
() =>
|
||||||
|
queryCalendarElement(`[data-calendar-week-start-key="${rowStartKey}"]`) ??
|
||||||
|
queryCalendarElement(`[data-calendar-day-key="${anchorDayKey}"]`),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2924,7 +2943,7 @@ async function zoomInCalendar(event?: Event) {
|
|||||||
if (maybePrimeWheelZoom(wheelEvent, calendarPrimeDayToken(dayAnchor))) return;
|
if (maybePrimeWheelZoom(wheelEvent, calendarPrimeDayToken(dayAnchor))) return;
|
||||||
await animateCalendarZoomIn(sourceElement, zoomGhostForDay(dayAnchor), () => {
|
await animateCalendarZoomIn(sourceElement, zoomGhostForDay(dayAnchor), () => {
|
||||||
openDayView(dayAnchor);
|
openDayView(dayAnchor);
|
||||||
});
|
}, () => queryCalendarElement(`[data-calendar-day-key="${dayAnchor}"]`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2935,6 +2954,7 @@ async function zoomToMonth(monthIndex: number) {
|
|||||||
() => {
|
() => {
|
||||||
openYearMonth(monthIndex);
|
openYearMonth(monthIndex);
|
||||||
},
|
},
|
||||||
|
() => queryCalendarElement(`[data-calendar-month-index="${monthIndex}"]`),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3366,6 +3386,7 @@ function openDocumentsTab(push = false) {
|
|||||||
const peopleListMode = ref<"contacts" | "deals">("contacts");
|
const peopleListMode = ref<"contacts" | "deals">("contacts");
|
||||||
const peopleSearch = ref("");
|
const peopleSearch = ref("");
|
||||||
const peopleSortMode = ref<PeopleSortMode>("lastContact");
|
const peopleSortMode = ref<PeopleSortMode>("lastContact");
|
||||||
|
const peopleVisibilityMode = ref<PeopleVisibilityMode>("all");
|
||||||
const brokenAvatarByContactId = ref<Record<string, boolean>>({});
|
const brokenAvatarByContactId = ref<Record<string, boolean>>({});
|
||||||
const peopleSortOptions: Array<{ value: PeopleSortMode; label: string }> = [
|
const peopleSortOptions: Array<{ value: PeopleSortMode; label: string }> = [
|
||||||
{ value: "lastContact", label: "Last contact" },
|
{ value: "lastContact", label: "Last contact" },
|
||||||
@@ -3373,6 +3394,10 @@ const peopleSortOptions: Array<{ value: PeopleSortMode; label: string }> = [
|
|||||||
{ value: "company", label: "Company" },
|
{ value: "company", label: "Company" },
|
||||||
{ value: "country", label: "Country" },
|
{ value: "country", label: "Country" },
|
||||||
];
|
];
|
||||||
|
const peopleVisibilityOptions: Array<{ value: PeopleVisibilityMode; label: string }> = [
|
||||||
|
{ value: "all", label: "All" },
|
||||||
|
{ value: "hidden", label: "Hidden" },
|
||||||
|
];
|
||||||
const selectedDealId = ref(deals.value[0]?.id ?? "");
|
const selectedDealId = ref(deals.value[0]?.id ?? "");
|
||||||
const selectedDealStepsExpanded = ref(false);
|
const selectedDealStepsExpanded = ref(false);
|
||||||
|
|
||||||
@@ -3412,26 +3437,54 @@ const commThreads = computed(() => {
|
|||||||
map.get(item.contact)?.push(item);
|
map.get(item.contact)?.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return contacts.value
|
const contactById = new Map(contacts.value.map((contact) => [contact.id, contact]));
|
||||||
.map((contact) => {
|
const inboxesByContactId = new Map<string, ContactInbox[]>();
|
||||||
const items = map.get(contact.name) ?? [];
|
for (const inbox of contactInboxes.value) {
|
||||||
|
if (!inboxesByContactId.has(inbox.contactId)) {
|
||||||
|
inboxesByContactId.set(inbox.contactId, []);
|
||||||
|
}
|
||||||
|
inboxesByContactId.get(inbox.contactId)?.push(inbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contactIds = new Set<string>([
|
||||||
|
...contacts.value.map((contact) => contact.id),
|
||||||
|
...contactInboxes.value.map((inbox) => inbox.contactId),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [...contactIds]
|
||||||
|
.map((contactId) => {
|
||||||
|
const contact = contactById.get(contactId);
|
||||||
|
const inboxes = inboxesByContactId.get(contactId) ?? [];
|
||||||
|
const contactName = contact?.name ?? inboxes[0]?.contactName ?? "";
|
||||||
|
const items = map.get(contactName) ?? [];
|
||||||
const last = items[items.length - 1];
|
const last = items[items.length - 1];
|
||||||
const channels = [...new Set([...contact.channels, ...items.map((item) => item.channel)])] as CommItem["channel"][];
|
const channels = [
|
||||||
|
...new Set([
|
||||||
|
...(contact?.channels ?? []),
|
||||||
|
...inboxes.map((inbox) => inbox.channel),
|
||||||
|
...items.map((item) => item.channel),
|
||||||
|
]),
|
||||||
|
] as CommItem["channel"][];
|
||||||
|
const inboxFallbackLast = inboxes
|
||||||
|
.map((inbox) => inbox.lastMessageAt || inbox.updatedAt)
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort()
|
||||||
|
.at(-1);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: contact.id,
|
id: contactId,
|
||||||
contact: contact.name,
|
contact: contactName,
|
||||||
avatar: contact.avatar,
|
avatar: contact?.avatar ?? "",
|
||||||
company: contact.company,
|
company: contact?.company ?? "",
|
||||||
country: contact.country,
|
country: contact?.country ?? "",
|
||||||
location: contact.location,
|
location: contact?.location ?? "",
|
||||||
channels,
|
channels,
|
||||||
lastAt: last?.at ?? contact.lastContactAt,
|
lastAt: last?.at ?? contact?.lastContactAt ?? inboxFallbackLast ?? "",
|
||||||
lastText: last?.text ?? "No messages yet",
|
lastText: last?.text ?? "No messages yet",
|
||||||
items,
|
items,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((thread) => thread.items.length > 0)
|
.filter((thread) => thread.contact)
|
||||||
.sort((a, b) => b.lastAt.localeCompare(a.lastAt));
|
.sort((a, b) => b.lastAt.localeCompare(a.lastAt));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3442,8 +3495,12 @@ const peopleContactList = computed(() => {
|
|||||||
const haystack = [item.contact, item.company, item.country, item.location].join(" ").toLowerCase();
|
const haystack = [item.contact, item.company, item.country, item.location].join(" ").toLowerCase();
|
||||||
return haystack.includes(query);
|
return haystack.includes(query);
|
||||||
});
|
});
|
||||||
|
const byVisibility = list.filter((item) => {
|
||||||
|
if (peopleVisibilityMode.value === "all") return true;
|
||||||
|
return threadInboxes(item).some((inbox) => inbox.isHidden);
|
||||||
|
});
|
||||||
|
|
||||||
return list.sort((a, b) => {
|
return byVisibility.sort((a, b) => {
|
||||||
if (peopleSortMode.value === "name") return a.contact.localeCompare(b.contact);
|
if (peopleSortMode.value === "name") return a.contact.localeCompare(b.contact);
|
||||||
if (peopleSortMode.value === "company") return a.company.localeCompare(b.company);
|
if (peopleSortMode.value === "company") return a.company.localeCompare(b.company);
|
||||||
if (peopleSortMode.value === "country") return a.country.localeCompare(b.country);
|
if (peopleSortMode.value === "country") return a.country.localeCompare(b.country);
|
||||||
@@ -4853,7 +4910,6 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
:on-calendar-hierarchy-wheel="onCalendarHierarchyWheel"
|
:on-calendar-hierarchy-wheel="onCalendarHierarchyWheel"
|
||||||
:set-calendar-scene-ref="setCalendarSceneRef"
|
:set-calendar-scene-ref="setCalendarSceneRef"
|
||||||
:normalized-calendar-view="normalizedCalendarView"
|
:normalized-calendar-view="normalizedCalendarView"
|
||||||
:calendar-scene-masked="calendarSceneMasked"
|
|
||||||
:calendar-scene-transform-style="calendarSceneTransformStyle"
|
:calendar-scene-transform-style="calendarSceneTransformStyle"
|
||||||
:on-calendar-scene-mouse-leave="onCalendarSceneMouseLeave"
|
:on-calendar-scene-mouse-leave="onCalendarSceneMouseLeave"
|
||||||
:calendar-view="calendarView"
|
:calendar-view="calendarView"
|
||||||
@@ -4894,6 +4950,8 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
:people-search="peopleSearch"
|
:people-search="peopleSearch"
|
||||||
:people-sort-options="peopleSortOptions"
|
:people-sort-options="peopleSortOptions"
|
||||||
:people-sort-mode="peopleSortMode"
|
:people-sort-mode="peopleSortMode"
|
||||||
|
:people-visibility-options="peopleVisibilityOptions"
|
||||||
|
:people-visibility-mode="peopleVisibilityMode"
|
||||||
:people-contact-list="peopleContactList"
|
:people-contact-list="peopleContactList"
|
||||||
:selected-comm-thread-id="selectedCommThreadId"
|
:selected-comm-thread-id="selectedCommThreadId"
|
||||||
:is-review-highlighted-contact="isReviewHighlightedContact"
|
:is-review-highlighted-contact="isReviewHighlightedContact"
|
||||||
@@ -4915,6 +4973,7 @@ async function decideFeedCard(card: FeedCard, decision: "accepted" | "rejected")
|
|||||||
:on-people-list-mode-change="(mode) => { peopleListMode = mode; }"
|
:on-people-list-mode-change="(mode) => { peopleListMode = mode; }"
|
||||||
:on-people-search-input="(value) => { peopleSearch = value; }"
|
:on-people-search-input="(value) => { peopleSearch = value; }"
|
||||||
:on-people-sort-mode-change="(mode) => { peopleSortMode = mode; }"
|
:on-people-sort-mode-change="(mode) => { peopleSortMode = mode; }"
|
||||||
|
:on-people-visibility-mode-change="(mode) => { peopleVisibilityMode = mode; }"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="hidden h-12 items-center justify-between gap-2 border-b border-base-300 px-3 md:flex md:col-span-2">
|
<div class="hidden h-12 items-center justify-between gap-2 border-b border-base-300 px-3 md:flex md:col-span-2">
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ defineProps<{
|
|||||||
onCalendarHierarchyWheel: (event: WheelEvent) => void;
|
onCalendarHierarchyWheel: (event: WheelEvent) => void;
|
||||||
setCalendarSceneRef: (element: HTMLDivElement | null) => void;
|
setCalendarSceneRef: (element: HTMLDivElement | null) => void;
|
||||||
normalizedCalendarView: string;
|
normalizedCalendarView: string;
|
||||||
calendarSceneMasked: boolean;
|
|
||||||
calendarSceneTransformStyle: Record<string, string>;
|
calendarSceneTransformStyle: Record<string, string>;
|
||||||
onCalendarSceneMouseLeave: () => void;
|
onCalendarSceneMouseLeave: () => void;
|
||||||
calendarView: string;
|
calendarView: string;
|
||||||
@@ -170,7 +169,6 @@ defineProps<{
|
|||||||
:class="[
|
:class="[
|
||||||
'calendar-scene',
|
'calendar-scene',
|
||||||
normalizedCalendarView === 'day' ? 'cursor-zoom-out' : 'cursor-zoom-in',
|
normalizedCalendarView === 'day' ? 'cursor-zoom-out' : 'cursor-zoom-in',
|
||||||
calendarSceneMasked ? 'calendar-scene-hidden' : '',
|
|
||||||
]"
|
]"
|
||||||
:style="calendarSceneTransformStyle"
|
:style="calendarSceneTransformStyle"
|
||||||
@mouseleave="onCalendarSceneMouseLeave"
|
@mouseleave="onCalendarSceneMouseLeave"
|
||||||
@@ -351,10 +349,6 @@ defineProps<{
|
|||||||
transform-origin: center center;
|
transform-origin: center center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-scene-hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-scene.cursor-zoom-in,
|
.calendar-scene.cursor-zoom-in,
|
||||||
.calendar-scene.cursor-zoom-in * {
|
.calendar-scene.cursor-zoom-in * {
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ defineProps<{
|
|||||||
peopleSearch: string;
|
peopleSearch: string;
|
||||||
peopleSortOptions: Array<{ value: string; label: string }>;
|
peopleSortOptions: Array<{ value: string; label: string }>;
|
||||||
peopleSortMode: string;
|
peopleSortMode: string;
|
||||||
|
peopleVisibilityOptions: Array<{ value: string; label: string }>;
|
||||||
|
peopleVisibilityMode: string;
|
||||||
peopleContactList: any[];
|
peopleContactList: any[];
|
||||||
selectedCommThreadId: string;
|
selectedCommThreadId: string;
|
||||||
isReviewHighlightedContact: (contactId: string) => boolean;
|
isReviewHighlightedContact: (contactId: string) => boolean;
|
||||||
@@ -26,6 +28,7 @@ defineProps<{
|
|||||||
onPeopleListModeChange: (mode: PeopleListMode) => void;
|
onPeopleListModeChange: (mode: PeopleListMode) => void;
|
||||||
onPeopleSearchInput: (value: string) => void;
|
onPeopleSearchInput: (value: string) => void;
|
||||||
onPeopleSortModeChange: (mode: string) => void;
|
onPeopleSortModeChange: (mode: string) => void;
|
||||||
|
onPeopleVisibilityModeChange: (mode: string) => void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
function onSearchInput(event: Event) {
|
function onSearchInput(event: Event) {
|
||||||
@@ -91,6 +94,17 @@ function onSearchInput(event: Event) {
|
|||||||
<span>{{ option.label }}</span>
|
<span>{{ option.label }}</span>
|
||||||
<span v-if="peopleSortMode === option.value">✓</span>
|
<span v-if="peopleSortMode === option.value">✓</span>
|
||||||
</button>
|
</button>
|
||||||
|
<div class="my-1 h-px bg-base-300/70" />
|
||||||
|
<p class="px-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-base-content/55">Filter contacts</p>
|
||||||
|
<button
|
||||||
|
v-for="option in peopleVisibilityOptions"
|
||||||
|
:key="`people-visibility-${option.value}`"
|
||||||
|
class="btn btn-ghost btn-sm w-full justify-between"
|
||||||
|
@click="onPeopleVisibilityModeChange(option.value)"
|
||||||
|
>
|
||||||
|
<span>{{ option.label }}</span>
|
||||||
|
<span v-if="peopleVisibilityMode === option.value">✓</span>
|
||||||
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<p v-else class="px-2 py-1 text-xs text-base-content/60">Deals are sorted by title.</p>
|
<p v-else class="px-2 py-1 text-xs text-base-content/60">Deals are sorted by title.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -192,7 +206,7 @@ function onSearchInput(event: Event) {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<p v-if="peopleListMode === 'contacts' && peopleContactList.length === 0" class="px-1 py-2 text-xs text-base-content/55">
|
<p v-if="peopleListMode === 'contacts' && peopleContactList.length === 0" class="px-1 py-2 text-xs text-base-content/55">
|
||||||
No contacts found.
|
{{ peopleVisibilityMode === 'hidden' ? 'No hidden contacts found.' : 'No contacts found.' }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="peopleListMode === 'deals' && peopleDealList.length === 0" class="px-1 py-2 text-xs text-base-content/55">
|
<p v-if="peopleListMode === 'deals' && peopleDealList.length === 0" class="px-1 py-2 text-xs text-base-content/55">
|
||||||
No deals found.
|
No deals found.
|
||||||
|
|||||||
Reference in New Issue
Block a user