Skip to content

Commit 74ee41e

Browse files
authored
Copilot/suggest descriptive names (#201)
2 parents 1785c9b + 70027f6 commit 74ee41e

8 files changed

Lines changed: 190 additions & 190 deletions

File tree

node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/AIConcierge.tsx

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type MessageContent =
1515
| { type: "text"; text: string }
1616
| { type: "image_url"; image_url: { url: string } };
1717

18-
type Msg = {
18+
type ChatMessage = {
1919
role: "user" | "assistant";
2020
content: string | MessageContent[];
2121
persona?: string;
@@ -28,9 +28,9 @@ const CHAT_URL = `${SUPABASE_URL}/functions/v1/beauty-assistant`;
2828
function getTextContent(content: string | MessageContent[]): string {
2929
if (typeof content === "string") return content;
3030
return content
31-
.filter((p): p is { type: "text"; text: string } => (p as { type: string }).type === "text")
32-
.filter((p): p is { type: "text"; text: string } => typeof p === "object" && p !== null && "type" in p && p.type === "text")
33-
.map((p) => p.text)
31+
.filter((contentPart): contentPart is { type: "text"; text: string } => (contentPart as { type: string }).type === "text")
32+
.filter((contentPart): contentPart is { type: "text"; text: string } => typeof contentPart === "object" && contentPart !== null && "type" in contentPart && contentPart.type === "text")
33+
.map((contentPart) => contentPart.text)
3434
.join(" ");
3535
}
3636

@@ -44,25 +44,25 @@ async function streamChat({
4444
onDone,
4545
onSafetyFlags,
4646
}: {
47-
messages: Msg[];
47+
messages: ChatMessage[];
4848
forcePersona?: string;
4949
userProfile?: { skin_type: string | null; skin_concern: string; tags: string[] } | null;
5050
campaignSource?: string | null;
51-
onPersona: (p: string) => void;
51+
onPersona: (persona: string) => void;
5252
onDelta: (text: string) => void;
5353
onDone: () => void;
5454
onSafetyFlags?: (flags: string[]) => void;
5555
}) {
56-
const payload = messages.map((m) => ({
57-
role: m.role,
58-
content: m.content,
56+
const payload = messages.map((chatMessage) => ({
57+
role: chatMessage.role,
58+
content: chatMessage.content,
5959
}));
6060

6161
const { data: { session } } = await supabase.auth.getSession();
6262
const token = session?.access_token;
6363
if (!token) throw new Error("Please sign in to use the AI concierge.");
6464

65-
const resp = await fetch(CHAT_URL, {
65+
const chatResponse = await fetch(CHAT_URL, {
6666
method: "POST",
6767
headers: {
6868
"Content-Type": "application/json",
@@ -71,37 +71,37 @@ async function streamChat({
7171
body: JSON.stringify({ messages: payload, forcePersona, userProfile, ...(campaignSource ? { source: campaignSource } : {}) }),
7272
});
7373

74-
if (!resp.ok) {
75-
const err = await resp.json().catch(() => ({ error: "Connection failed" }));
76-
throw new Error(err.error || `Error ${resp.status}`);
74+
if (!chatResponse.ok) {
75+
const errorResponse = await chatResponse.json().catch(() => ({ error: "Connection failed" }));
76+
throw new Error(errorResponse.error || `Error ${chatResponse.status}`);
7777
}
7878

79-
const persona = resp.headers.get("X-Persona");
79+
const persona = chatResponse.headers.get("X-Persona");
8080
if (persona) onPersona(persona);
8181

82-
const safetyFlags = resp.headers.get("X-Safety-Flags");
82+
const safetyFlags = chatResponse.headers.get("X-Safety-Flags");
8383
if (safetyFlags && safetyFlags !== "none" && onSafetyFlags) {
8484
onSafetyFlags(safetyFlags.split(","));
8585
}
8686

87-
if (!resp.body) throw new Error("No response body");
87+
if (!chatResponse.body) throw new Error("No response body");
8888

89-
const reader = resp.body.getReader();
89+
const reader = chatResponse.body.getReader();
9090
const decoder = new TextDecoder();
91-
let buffer = "";
91+
let streamBuffer = "";
9292

9393
while (true) {
9494
const { done, value } = await reader.read();
9595
if (done) break;
96-
buffer += decoder.decode(value, { stream: true });
97-
98-
let idx: number;
99-
while ((idx = buffer.indexOf("\n")) !== -1) {
100-
let line = buffer.slice(0, idx);
101-
buffer = buffer.slice(idx + 1);
102-
if (line.endsWith("\r")) line = line.slice(0, -1);
103-
if (!line.startsWith("data: ")) continue;
104-
const json = line.slice(6).trim();
96+
streamBuffer += decoder.decode(value, { stream: true });
97+
98+
let newlineIndex: number;
99+
while ((newlineIndex = streamBuffer.indexOf("\n")) !== -1) {
100+
let sseDataLine = streamBuffer.slice(0, newlineIndex);
101+
streamBuffer = streamBuffer.slice(newlineIndex + 1);
102+
if (sseDataLine.endsWith("\r")) sseDataLine = sseDataLine.slice(0, -1);
103+
if (!sseDataLine.startsWith("data: ")) continue;
104+
const json = sseDataLine.slice(6).trim();
105105
if (json === "[DONE]") {
106106
onDone();
107107
return;
@@ -111,7 +111,7 @@ async function streamChat({
111111
const content = parsed.choices?.[0]?.delta?.content;
112112
if (content) onDelta(content);
113113
} catch {
114-
buffer = line + "\n" + buffer;
114+
streamBuffer = sseDataLine + "\n" + streamBuffer;
115115
break;
116116
}
117117
}
@@ -185,7 +185,7 @@ const quickPrompts = [
185185

186186
export default function AIConcierge() {
187187
const [open, setOpen] = useState(false);
188-
const [messages, setMessages] = useState<Msg[]>([]);
188+
const [messages, setMessages] = useState<ChatMessage[]>([]);
189189
const [input, setInput] = useState("");
190190
const [isLoading, setIsLoading] = useState(false);
191191
const [currentPersona, setCurrentPersona] = useState<string>("ms_zain");
@@ -358,7 +358,7 @@ export default function AIConcierge() {
358358
userContent = text.trim();
359359
}
360360

361-
const userMsg: Msg = { role: "user", content: userContent, imagePreview };
361+
const userMsg: ChatMessage = { role: "user", content: userContent, imagePreview };
362362
setMessages((prev) => [...prev, userMsg]);
363363
setInput("");
364364
setIsLoading(true);
@@ -371,8 +371,8 @@ export default function AIConcierge() {
371371
setMessages((prev) => {
372372
const last = prev[prev.length - 1];
373373
if (last?.role === "assistant") {
374-
return prev.map((m, i) =>
375-
i === prev.length - 1 ? { ...m, content: assistantSoFar, persona: detectedPersona } : m
374+
return prev.map((chatMessage, messageIndex) =>
375+
messageIndex === prev.length - 1 ? { ...chatMessage, content: assistantSoFar, persona: detectedPersona } : chatMessage
376376
);
377377
}
378378
return [...prev, { role: "assistant", content: assistantSoFar, persona: detectedPersona }];
@@ -384,9 +384,9 @@ export default function AIConcierge() {
384384
messages: [...messages, userMsg],
385385
userProfile,
386386
campaignSource: deepLinkSource.current,
387-
onPersona: (p) => {
388-
detectedPersona = p;
389-
setCurrentPersona(p);
387+
onPersona: (detectedPersonaId) => {
388+
detectedPersona = detectedPersonaId;
389+
setCurrentPersona(detectedPersonaId);
390390
},
391391
onDelta: upsert,
392392
onDone: () => { setIsLoading(false); playNotificationSound(); },

src/components/AsperAccessCard.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ export default function AsperAccessCard({ name = "Guest", protocol = "HYDRATION"
2525
if (isFlipped) return;
2626
const card = e.currentTarget;
2727
const box = card.getBoundingClientRect();
28-
const x = e.clientX - box.left;
29-
const y = e.clientY - box.top;
28+
const mouseX = e.clientX - box.left;
29+
const mouseY = e.clientY - box.top;
3030
const centerX = box.width / 2;
3131
const centerY = box.height / 2;
32-
setRotateX(((y - centerY) / centerY) * -15);
33-
setRotateY(((x - centerX) / centerX) * 15);
34-
setGlareX((x / box.width) * 100);
35-
setGlareY((y / box.height) * 100);
32+
setRotateX(((mouseY - centerY) / centerY) * -15);
33+
setRotateY(((mouseX - centerX) / centerX) * 15);
34+
setGlareX((mouseX / box.width) * 100);
35+
setGlareY((mouseY / box.height) * 100);
3636
};
3737

3838
const handleMouseLeave = () => {
@@ -60,9 +60,9 @@ export default function AsperAccessCard({ name = "Guest", protocol = "HYDRATION"
6060
];
6161

6262
const personaColor = (persona: string) => {
63-
const lower = persona.toLowerCase();
64-
if (lower.includes("sami") || lower === "dr_sami") return "text-burgundy";
65-
if (lower.includes("zain") || lower === "ms_zain") return "text-polished-gold";
63+
const lowerCasePersona = persona.toLowerCase();
64+
if (lowerCasePersona.includes("sami") || lowerCasePersona === "dr_sami") return "text-burgundy";
65+
if (lowerCasePersona.includes("zain") || lowerCasePersona === "ms_zain") return "text-polished-gold";
6666
return "text-burgundy";
6767
};
6868

src/components/AudioWaveformReplay.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ const NUM_BARS = BAR_HEIGHTS.length;
4242

4343
function formatTime(secs: number): string {
4444
if (!isFinite(secs) || secs <= 0) return "0:00";
45-
const m = Math.floor(secs / 60);
46-
const s = Math.floor(secs % 60);
47-
return `${m}:${s.toString().padStart(2, "0")}`;
45+
const minutes = Math.floor(secs / 60);
46+
const remainingSeconds = Math.floor(secs % 60);
47+
return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
4848
}
4949

5050
const PERSONA_LABELS: Record<string, { name: string; title: string }> = {
@@ -115,11 +115,11 @@ export const AudioWaveformReplay: React.FC<AudioWaveformReplayProps> = ({
115115
{isLoading ? (
116116
/* Loading state — shimmer bars */
117117
<div className="flex items-end gap-[2px] w-full h-full px-1">
118-
{BAR_HEIGHTS.map((h, i) => (
118+
{BAR_HEIGHTS.map((barHeight, barIndex) => (
119119
<div
120-
key={i}
120+
key={barIndex}
121121
className="flex-1 rounded-sm bg-[#800020]/20 animate-pulse"
122-
style={{ height: `${(h / 95) * 100}%` }}
122+
style={{ height: `${(barHeight / 95) * 100}%` }}
123123
/>
124124
))}
125125
</div>
@@ -129,14 +129,14 @@ export const AudioWaveformReplay: React.FC<AudioWaveformReplayProps> = ({
129129
</p>
130130
) : (
131131
<div className="flex items-end gap-[2px] w-full h-full px-1">
132-
{BAR_HEIGHTS.map((h, i) => {
133-
const isActive = i < activeBars;
134-
const isCurrent = i === activeBars;
135-
const heightPct = `${(h / 95) * 100}%`;
132+
{BAR_HEIGHTS.map((barHeight, barIndex) => {
133+
const isActive = barIndex < activeBars;
134+
const isCurrent = barIndex === activeBars;
135+
const heightPct = `${(barHeight / 95) * 100}%`;
136136

137137
return (
138138
<div
139-
key={i}
139+
key={barIndex}
140140
className={cn(
141141
"flex-1 rounded-sm transition-all duration-100",
142142
isActive

0 commit comments

Comments
 (0)