fix(workspace): guard trim calls against undefined data

This commit is contained in:
Ruslan Bakiev
2026-02-23 11:51:55 +07:00
parent 8be6e7d581
commit 5918a0593d

View File

@@ -170,6 +170,10 @@ type ClientTimelineItem = {
const selectedTab = ref<TabId>("communications"); const selectedTab = ref<TabId>("communications");
const peopleLeftMode = ref<PeopleLeftMode>("contacts"); const peopleLeftMode = ref<PeopleLeftMode>("contacts");
function safeTrim(value: unknown) {
return String(value ?? "").trim();
}
function dayKey(date: Date) { function dayKey(date: Date) {
const y = date.getFullYear(); const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, "0"); const m = String(date.getMonth() + 1).padStart(2, "0");
@@ -817,7 +821,7 @@ function normalizePilotTimeline(messages: PilotMessage[]) {
const renderedPilotMessages = computed<PilotMessage[]>(() => { const renderedPilotMessages = computed<PilotMessage[]>(() => {
const items = normalizePilotTimeline(pilotMessages.value).filter((m) => m.role !== "system"); const items = normalizePilotTimeline(pilotMessages.value).filter((m) => m.role !== "system");
const hasPersistedLiveUser = items.some( const hasPersistedLiveUser = items.some(
(m) => m.role === "user" && m.text.trim() === livePilotUserText.value.trim(), (m) => m.role === "user" && safeTrim(m.text) === livePilotUserText.value.trim(),
); );
if (livePilotUserText.value && !hasPersistedLiveUser) { if (livePilotUserText.value && !hasPersistedLiveUser) {
@@ -1172,7 +1176,7 @@ function startCrmRealtime() {
} }
async function sendPilotText(rawText: string) { async function sendPilotText(rawText: string) {
const text = rawText.trim(); const text = safeTrim(rawText);
if (!text || pilotSending.value) return; if (!text || pilotSending.value) return;
const contextPayload = buildContextPayload(); const contextPayload = buildContextPayload();
@@ -1396,7 +1400,7 @@ async function startPilotMeter(stream: MediaStream) {
} }
function appendPilotTranscript(text: string) { function appendPilotTranscript(text: string) {
const next = text.trim(); const next = safeTrim(text);
if (!next) return ""; if (!next) return "";
const merged = pilotInput.value.trim() ? `${pilotInput.value.trim()} ${next}` : next; const merged = pilotInput.value.trim() ? `${pilotInput.value.trim()} ${next}` : next;
pilotInput.value = merged; pilotInput.value = merged;
@@ -1831,7 +1835,7 @@ function parseCalendarYearToken(token: string | null | undefined) {
} }
function normalizedConversationId() { function normalizedConversationId() {
return (selectedChatId.value || authMe.value?.conversation.id || "pilot").trim(); return safeTrim(selectedChatId.value || authMe.value?.conversation.id || "pilot");
} }
function currentUiPath() { function currentUiPath() {
@@ -4041,8 +4045,8 @@ const selectedWorkspaceDeal = computed(() => {
}); });
function formatDealHeadline(deal: Deal) { function formatDealHeadline(deal: Deal) {
const title = deal.title.trim(); const title = safeTrim(deal.title);
const amountRaw = deal.amount.trim(); const amountRaw = safeTrim(deal.amount);
if (!amountRaw) return title; if (!amountRaw) return title;
const normalized = amountRaw.replace(/\s+/g, "").replace(",", "."); const normalized = amountRaw.replace(/\s+/g, "").replace(",", ".");
@@ -4066,7 +4070,7 @@ function getDealCurrentStep(deal: Deal) {
} }
function getDealCurrentStepLabel(deal: Deal) { function getDealCurrentStepLabel(deal: Deal) {
return getDealCurrentStep(deal)?.title?.trim() || deal.nextStep.trim() || deal.stage.trim() || "Без шага"; return safeTrim(getDealCurrentStep(deal)?.title) || safeTrim(deal.nextStep) || safeTrim(deal.stage) || "Без шага";
} }
function parseDateFromText(input: string) { function parseDateFromText(input: string) {
@@ -4584,7 +4588,7 @@ async function createCommDocument() {
return; return;
} }
const title = commDocumentForm.value.title.trim() || buildCommDocumentTitle(summary, selectedCommThread.value.contact); const title = safeTrim(commDocumentForm.value.title) || buildCommDocumentTitle(summary, selectedCommThread.value.contact);
const scope = buildContactDocumentScope(selectedCommThread.value.id, selectedCommThread.value.contact); const scope = buildContactDocumentScope(selectedCommThread.value.id, selectedCommThread.value.contact);
const body = summary; const body = summary;