2import React, { useState, useEffect } from "https://esm.sh/react@18.2.0";
3import { ValGrid } from "./ValGrid.tsx";
4import { fetchMoiConfig, getProfileImageUrl } from "../utils/moiConfig.tsx";
5
6interface UserProfileProps {
15 username: string;
16 description: string | null;
17 image_url: string | null;
18 forked_branch_id: string | null;
19 updated_at: string;
33 const [currentPage, setCurrentPage] = useState(1);
34 const [moiConfig, setMoiConfig] = useState<any>(null);
35 const [profileImageError, setProfileImageError] = useState(false);
36
37 // Generate a deterministic background color based on username
77 const data = await profileResponse.json();
78
79 // If we have moi config with imageUrl, update the profile data
80 if (config && config.imageUrl) {
81 // Process each val result to enhance its image_url if needed
82 if (data.valResults && data.valResults.length > 0) {
83 data.valResults = data.valResults.map(val => {
84 // For vals with the same username as the profile, apply the moi config imageUrl
85 // This helps with personal projects
86 if (val.username === username && !val.image_url) {
87 return {
88 ...val,
89 image_url: config.imageUrl
90 };
91 }
149 }
150
151 // Get profile image URL with potential moi config override
152 const profileImageUrl = !profileImageError
153 ? getProfileImageUrl(username, moiConfig, null)
154 : null;
155
162 <div
163 className="w-28 h-28 md:w-36 md:h-36 overflow-hidden rounded-full border-2 border-gray-200 flex items-center justify-center"
164 style={{ backgroundColor: profileImageError || !profileImageUrl ? profileColor : undefined }}
165 >
166 {profileImageUrl ? (
167 <img
168 src={profileImageUrl}
169 alt={`@${username}'s profile`}
170 className="w-full h-full object-cover"
171 onError={() => setProfileImageError(true)}
172 />
173 ) : (
206 </div>
207
208 {/* Image Grid */}
209 <ValGrid vals={profileData.valResults} />
210
101 fileCount: number;
102 url: string;
103 profile_image_url: string | null;
104 updated_at: string;
105}[]> {
110 COUNT(DISTINCT f.id) as file_count,
111 'https://val.town/u/' || p.username as url,
112 u.profile_image_url,
113 MAX(p.updated_at) as updated_at
114 FROM ${tablePrefix}_vals p
126 fileCount: Number(row.file_count),
127 url: String(row.url),
128 profile_image_url: row.profile_image_url ? String(row.profile_image_url) : null,
129 updated_at: String(row.updated_at),
130 }));
140 description: string | null;
141 url: string;
142 image_url: string | null;
143 updated_at: string;
144}[]> {
150 p.description,
151 p.url,
152 p.image_url,
153 p.updated_at
154 FROM ${tablePrefix}_vals p
166 description: row.description ? String(row.description) : null,
167 url: String(row.url),
168 image_url: row.image_url ? String(row.image_url) : null,
169 updated_at: String(row.updated_at),
170 }));
186 fileCount: number;
187 url: string;
188 profile_image_url: string | null;
189 updated_at: string;
190 }[];
195 description: string | null;
196 url: string;
197 image_url: string | null;
198 updated_at: string;
199 }[];
275 username TEXT,
276 bio TEXT,
277 profile_image_url TEXT,
278 url TEXT NOT NULL,
279 updated_at TIMESTAMP NOT NULL
289 forked_branch_id TEXT,
290 description TEXT,
291 image_url TEXT,
292 user_id TEXT,
293 FOREIGN KEY (user_id) REFERENCES ${tablePrefix}_users(id)
320 username: z.string().nullable(),
321 bio: z.string().nullable(),
322 profile_image_url: z.string().nullable(),
323 url: z.string(),
324 updated_at: z.string().datetime(),
331 username: z.string(),
332 description: z.string().nullable(),
333 image_url: z.string().nullable(),
334 forked_branch_id: z.string().nullable(),
335 updated_at: z.string().datetime(),
394 // Insert new user
395 await sqlite.execute(
396 `INSERT INTO ${tablePrefix}_users (id, username, bio, profile_image_url, url, updated_at)
397 VALUES (?, ?, ?, ?, ?, ?)`,
398 [
400 user.username,
401 user.bio,
402 user.profile_image_url,
403 user.url,
404 user.updated_at,
410 await sqlite.execute(
411 `UPDATE ${tablePrefix}_users
412 SET username = ?, bio = ?, profile_image_url = ?, url = ?, updated_at = ?
413 WHERE id = ?`,
414 [
415 user.username,
416 user.bio,
417 user.profile_image_url,
418 user.url,
419 user.updated_at,
459 // Insert new val
460 await sqlite.execute(
461 `INSERT INTO ${tablePrefix}_vals (id, url, name, username, updated_at, forked_branch_id, description, image_url, user_id)
462 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
463 [
469 val.forked_branch_id,
470 val.description,
471 val.image_url,
472 val.user_id,
473 ],
478 await sqlite.execute(
479 `UPDATE ${tablePrefix}_vals
480 SET url = ?, name = ?, username = ?, updated_at = ?, forked_branch_id = ?, description = ?, image_url = ?, user_id = ?
481 WHERE id = ?`,
482 [
487 val.forked_branch_id,
488 val.description,
489 val.image_url,
490 val.user_id,
491 val.id,
819
820 const result = await sqlite.execute(
821 `SELECT u.id, u.username, u.bio, u.profile_image_url, u.url, u.updated_at,
822 (SELECT COUNT(*) FROM ${tablePrefix}_vals p
823 WHERE p.user_id = u.id) as matchCount
834 username: z.string().nullable(),
835 bio: z.string().nullable(),
836 profile_image_url: z.string().nullable(),
837 url: z.string(),
838 updated_at: z.string().datetime(),
897 // Always launch the files query for the active type or for samples
898 const result = await sqlite.execute(
899 `SELECT f.*, p.name as val_name, p.url as val_url, p.username, p.description, p.image_url
900 FROM ${tablePrefix}_files f
901 JOIN ${tablePrefix}_vals p ON f.val_id = p.id
912 username: z.string(),
913 description: z.string().nullable(),
914 image_url: z.string().nullable(),
915 });
916