+
+ {question.text}
+ {currentIdx + 1}/{survey.questions.length}
+
+
+ {question.type === "text" && (
+
handleAnswer(question.id, e.target.value)}
+ />
+ )}
+
+ {question.type === "rating" && (
+
+ {[1, 2, 3, 4, 5].map((n) => (
+
+ ))}
+
+ )}
+
+ {question.type === "choice" && question.options && (
+
+ {question.options.map((opt) => (
+
+ ))}
+
+ )}
+
+
+
+
+
+
+ );
+}
diff --git a/web/src/lib/broadcast-client.ts b/web/src/lib/broadcast-client.ts
new file mode 100644
index 0000000..b323f1f
--- /dev/null
+++ b/web/src/lib/broadcast-client.ts
@@ -0,0 +1,24 @@
+"use client";
+
+import { createBroadcastClient, type BroadcastClient } from "@bytelyst/broadcast-client";
+import { PLATFORM_SERVICE_URL, PRODUCT_ID } from "@/lib/product-config";
+
+function getAccessToken(): string {
+ if (typeof window === "undefined") return "";
+ return localStorage.getItem(`${PRODUCT_ID}_access_token`) ?? "";
+}
+
+let _client: BroadcastClient | null = null;
+export function getBroadcastClient(): BroadcastClient {
+ if (!_client) {
+ _client = createBroadcastClient({
+ baseUrl: PLATFORM_SERVICE_URL,
+ productId: PRODUCT_ID,
+ getAuthToken: getAccessToken,
+ platform: "web",
+ appVersion: "0.1.0",
+ osVersion: typeof navigator !== "undefined" ? navigator.userAgent.slice(0, 40) : "unknown",
+ });
+ }
+ return _client;
+}
diff --git a/web/src/lib/feedback-client.ts b/web/src/lib/feedback-client.ts
new file mode 100644
index 0000000..0942c9f
--- /dev/null
+++ b/web/src/lib/feedback-client.ts
@@ -0,0 +1,20 @@
+"use client";
+
+import { createFeedbackClient, type FeedbackClient } from "@bytelyst/feedback-client";
+import { PLATFORM_SERVICE_URL, PRODUCT_ID } from "@/lib/product-config";
+
+function getAccessToken(): string | null {
+ if (typeof window === "undefined") return null;
+ return localStorage.getItem(`${PRODUCT_ID}_access_token`);
+}
+
+let _client: FeedbackClient | null = null;
+export function getFeedbackClient(): FeedbackClient {
+ if (!_client) {
+ _client = createFeedbackClient({
+ baseUrl: PLATFORM_SERVICE_URL,
+ getAuthToken: () => getAccessToken() ?? "",
+ });
+ }
+ return _client;
+}
diff --git a/web/src/lib/offline-queue.ts b/web/src/lib/offline-queue.ts
new file mode 100644
index 0000000..7f27934
--- /dev/null
+++ b/web/src/lib/offline-queue.ts
@@ -0,0 +1,36 @@
+"use client";
+
+import { createOfflineQueue, type OfflineQueue } from "@bytelyst/offline-queue";
+import { PRODUCT_ID } from "@/lib/product-config";
+import { createNotesApiClient } from "@/lib/api-helpers";
+
+const ACTION_METHOD: Record