import { css, html } from "lit"; import { BaseElement } from "../../core/base-element.ts"; import { CTCharm } from "../ct-charm/ct-charm.ts"; import { Cell } from "@commontools/runner"; /** * CTUpdater - Button component for registering charms for background updates * * @element ct-updater * * @attr {Cell} state - Cell state object * @attr {string} integration - Integration name/identifier * * @example * */ export class CTUpdater extends BaseElement { static override styles = [ BaseElement.baseStyles, css` :host { --button-background: var( --ct-theme-color-primary, var(--ct-color-primary, #3b82f6) ); --button-color: var( --ct-theme-color-primary-foreground, var(--ct-color-white, #ffffff) ); --button-height: 2.5rem; --button-success-background: var( --ct-theme-color-success, var(--ct-color-green-600, #16a34a) ); --button-error-background: var( --ct-theme-color-error, var(--ct-color-red-600, #dc2626) ); display: block; } .button { align-items: center; appearance: none; background-color: var(--button-background); border: 0; box-sizing: border-box; border-radius: calc(var(--button-height) / 2); color: var(--button-color); cursor: pointer; display: flex; font-size: 0.875rem; font-family: var(--ct-theme-font-family, inherit); font-weight: 500; height: var(--button-height); justify-content: center; overflow: hidden; line-height: 1.25rem; padding: 0.5rem 1.25rem; text-align: center; text-wrap: nowrap; width: 100%; transition: all var(--ct-theme-animation-duration, 0.2s) ease; } .button[data-state="pending"] { cursor: wait; opacity: 0.7; } .button[data-state="success"] { background-color: var(--button-success-background); } .button[data-state="error"] { background-color: var(--button-error-background); } .button:hover:not([data-state="pending"]) { opacity: 0.9; transform: translateY(-1px); } .button:active:not([data-state="pending"]) { transform: translateY(0); } `, ]; static override properties = { state: { type: Object }, integration: { type: String }, }; declare state: Cell; declare integration: string; private updateState: "idle" | "pending" | "success" | "error" = "idle"; private async handleClick() { if (this.updateState === "pending") return; this.updateState = "pending"; this.requestUpdate(); const container = CTCharm.findCharmContainer(this); if (!container) { throw new Error("No container."); } const { charmId } = container; const space = this.state.space; const payload = { charmId, space, integration: this.integration!, }; try { const response = await fetch(`/api/integrations/bg`, { method: "POST", body: JSON.stringify(payload), }); const result = await response.json(); if (result.success) { this.updateState = "success"; } else { console.log("updater error", result); this.updateState = "error"; } } catch (error) { console.log("updater error", error); this.updateState = "error"; } this.requestUpdate(); // Reset state after 3 seconds setTimeout(() => { this.updateState = "idle"; this.requestUpdate(); }, 3000); } override render() { const buttonText = { idle: "Register Charm for Updates", pending: "Registering...", success: "Successfully Registered!", error: "Registration Failed", }[this.updateState]; return html` `; } } globalThis.customElements.define("ct-updater", CTUpdater);