refactor(line): dedupe schedule card header + bubble

This commit is contained in:
Peter Steinberger
2026-02-15 12:46:47 +00:00
parent 80abb5ab98
commit 216f4d4669

View File

@@ -1,6 +1,56 @@
import type { Action, FlexBox, FlexBubble, FlexComponent, FlexText } from "./types.js";
import { attachFooterText } from "./common.js";
function buildTitleSubtitleHeader(params: { title: string; subtitle?: string }): FlexComponent[] {
const { title, subtitle } = params;
const headerContents: FlexComponent[] = [
{
type: "text",
text: title,
weight: "bold",
size: "xl",
color: "#111111",
wrap: true,
} as FlexText,
];
if (subtitle) {
headerContents.push({
type: "text",
text: subtitle,
size: "sm",
color: "#888888",
margin: "sm",
wrap: true,
} as FlexText);
}
return headerContents;
}
function createMegaBubbleWithFooter(params: {
bodyContents: FlexComponent[];
footer?: string;
}): FlexBubble {
const bubble: FlexBubble = {
type: "bubble",
size: "mega",
body: {
type: "box",
layout: "vertical",
contents: params.bodyContents,
paddingAll: "xl",
backgroundColor: "#FFFFFF",
},
};
if (params.footer) {
attachFooterText(bubble, params.footer);
}
return bubble;
}
/**
* Create a receipt/summary card (for orders, transactions, data tables)
*
@@ -48,27 +98,7 @@ export function createReceiptCard(params: {
);
// Header section
const headerContents: FlexComponent[] = [
{
type: "text",
text: title,
weight: "bold",
size: "xl",
color: "#111111",
wrap: true,
} as FlexText,
];
if (subtitle) {
headerContents.push({
type: "text",
text: subtitle,
size: "sm",
color: "#888888",
margin: "sm",
wrap: true,
} as FlexText);
}
const headerContents = buildTitleSubtitleHeader({ title, subtitle });
const bodyContents: FlexComponent[] = [
{
@@ -123,23 +153,7 @@ export function createReceiptCard(params: {
} as FlexBox);
}
const bubble: FlexBubble = {
type: "bubble",
size: "mega",
body: {
type: "box",
layout: "vertical",
contents: bodyContents,
paddingAll: "xl",
backgroundColor: "#FFFFFF",
},
};
if (footer) {
attachFooterText(bubble, footer);
}
return bubble;
return createMegaBubbleWithFooter({ bodyContents, footer });
}
/**
@@ -338,27 +352,7 @@ export function createAgendaCard(params: {
const { title, subtitle, events, footer } = params;
// Header with title and optional subtitle
const headerContents: FlexComponent[] = [
{
type: "text",
text: title,
weight: "bold",
size: "xl",
color: "#111111",
wrap: true,
} as FlexText,
];
if (subtitle) {
headerContents.push({
type: "text",
text: subtitle,
size: "sm",
color: "#888888",
margin: "sm",
wrap: true,
} as FlexText);
}
const headerContents = buildTitleSubtitleHeader({ title, subtitle });
// Event timeline items
const eventItems: FlexComponent[] = events.slice(0, 6).map((event, index) => {
@@ -472,21 +466,5 @@ export function createAgendaCard(params: {
} as FlexBox,
];
const bubble: FlexBubble = {
type: "bubble",
size: "mega",
body: {
type: "box",
layout: "vertical",
contents: bodyContents,
paddingAll: "xl",
backgroundColor: "#FFFFFF",
},
};
if (footer) {
attachFooterText(bubble, footer);
}
return bubble;
return createMegaBubbleWithFooter({ bodyContents, footer });
}