diff --git a/src/components/ExistingLabProfileNotice.tsx b/src/components/ExistingLabProfileNotice.tsx
deleted file mode 100644
index 331ebac..0000000
--- a/src/components/ExistingLabProfileNotice.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { Link } from 'react-router-dom';
-import { AlertTriangle, Eye } from 'lucide-react';
-import { Button } from '@/components/ui/button';
-import { useCurrentUser } from '@/hooks/useCurrentUser';
-import { useLabProfile } from '@/hooks/useLabProfiles';
-
-/**
- * Lab provider profiles (coach, filmer, editor, photographer, builder…) are
- * addressable events keyed by a fixed `d` identifier per type
- * (e.g. "coach-profile"). That means re-publishing REPLACES the existing one.
- *
- * The "Become a …" forms start blank and don't reconstruct prior state, so a
- * returning provider who submits again would silently wipe every field they'd
- * set before (bio, rate, spots, contact…). This notice makes that consequence
- * explicit: it appears only when the current user already has a profile of this
- * type, warns that submitting will overwrite it, and links them to view it.
- */
-export function ExistingLabProfileNotice({
- identifier,
- label,
-}: {
- /** The fixed `d` identifier for this Lab profile type, e.g. "coach-profile". */
- identifier: string;
- /** Human label for the profile type, e.g. "coach". */
- label: string;
-}) {
- const { user } = useCurrentUser();
- const { data: existing } = useLabProfile(identifier, user?.pubkey);
-
- if (!user || !existing) return null;
-
- return (
-
-
-
-
-
- You already have a {label} profile
-
-
- Publishing this form replaces your
- current {label} profile — anything you don't re-enter here will be lost. Review your
- existing profile first so you don't drop details you already set.
-
-
-
-
-
- );
-}
diff --git a/src/pages/BecomeBuilderPage.tsx b/src/pages/BecomeBuilderPage.tsx
index 835763c..1b46ab2 100644
--- a/src/pages/BecomeBuilderPage.tsx
+++ b/src/pages/BecomeBuilderPage.tsx
@@ -1,4 +1,4 @@
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import { useSeoMeta } from '@unhead/react';
import { useNavigate, Link } from 'react-router-dom';
import ngeohash from 'ngeohash';
@@ -23,7 +23,6 @@ import { SpotPicker } from '@/components/SpotPicker';
import { NofferField } from '@/components/NofferField';
import { PaymentReadinessNote } from '@/components/PaymentReadinessNote';
import { EntityTypeField } from '@/components/EntityTypeField';
-import { ExistingLabProfileNotice } from '@/components/ExistingLabProfileNotice';
import { CrewLinkField } from '@/components/CrewLinkField';
import {
SKATE_BUILDER_KIND,
@@ -39,6 +38,7 @@ import { cn } from '@/lib/utils';
import { HardHat, Upload, X, Loader2, ArrowLeft, MapPin, Wallet, ExternalLink, Hammer } from 'lucide-react';
import { LabProUpgrade } from '@/components/LabProUpgrade';
import { usePlatformFee } from '@/hooks/usePlatformFee';
+import { useMyLabProfileEvent } from '@/hooks/useMyLabProfile';
const SERVICE_ENTRIES = Object.entries(BUILDER_SERVICE_LABELS);
const SKILL_ENTRIES = Object.entries(BUILDER_SKILL_LABELS);
@@ -116,6 +116,51 @@ export default function BecomeBuilderPage() {
const [crewRef, setCrewRef] = useState(undefined);
const [selectedSpots, setSelectedSpots] = useState([]);
const [isGettingLocation, setIsGettingLocation] = useState(false);
+ const [titleInput, setTitleInput] = useState('');
+ const [prefilled, setPrefilled] = useState(false);
+
+ // Prefill from an existing profile so this is an edit, not a blind overwrite.
+ const { data: existingProfile } = useMyLabProfileEvent(SKATE_BUILDER_KIND, 'builder-profile');
+ useEffect(() => {
+ if (prefilled || !existingProfile) return;
+ setPrefilled(true);
+ const tag = (n: string) => existingProfile.tags.find(([t]) => t === n)?.[1];
+ const tags = (n: string) => existingProfile.tags.filter(([t]) => t === n).map(([, v]) => v);
+ const keys = (m: Record) => new Set(Object.keys(m));
+ const svcK = keys(BUILDER_SERVICE_LABELS);
+ const skillK = keys(BUILDER_SKILL_LABELS);
+ const scaleK = keys(BUILDER_SCALE_LABELS);
+ const sel = tags('t').filter((v) => v !== 'skatebuilder');
+ setTitleInput(tag('title') ?? '');
+ setBio(existingProfile.content ?? '');
+ setLocation(tag('location') ?? '');
+ setImage(tag('image') ?? null);
+ setExperience(tag('experience') ?? '');
+ setRate(tag('rate') ?? '');
+ setPhone(tag('phone') ?? '');
+ setEmail(tag('email') ?? '');
+ setWebsite(tag('website') ?? '');
+ setPortfolio(tag('portfolio') ?? '');
+ setSocial(tag('social') ?? '');
+ setNoffer(tag('noffer') ?? '');
+ setGear(tag('gear') ?? '');
+ setServiceArea(tag('service_area') ?? '');
+ setInsured(tag('insured') === 'true');
+ setEntityType((tag('entity') as EntityType) ?? 'collective');
+ setMembers(tags('p'));
+ setCrewRef(existingProfile.tags.find(([t, v]) => t === 'a' && v.startsWith('35006:'))?.[1]);
+ setSelectedServices(sel.filter((v) => svcK.has(v)));
+ setSelectedSkills(sel.filter((v) => skillK.has(v)));
+ setSelectedScale(sel.filter((v) => scaleK.has(v)));
+ setSelectedSpots(
+ existingProfile.tags
+ .filter(([t, v]) => t === 'a' && v.startsWith(`${SKATE_SPOT_KIND}:`))
+ .map(([, v]) => {
+ const [, pk, ...rest] = v.split(':');
+ return `${pk}:${rest.join(':')}`;
+ }),
+ );
+ }, [existingProfile, prefilled]);
const getDisplayName = () => {
if (author.data?.metadata?.name) return author.data.metadata.name;
@@ -181,7 +226,7 @@ export default function BecomeBuilderPage() {
const tags: string[][] = [
['d', identifier],
- ['title', displayName],
+ ['title', titleInput.trim() || displayName],
['t', 'skatebuilder'],
['alt', `Skate ramp/park builder: ${displayName}`],
];
@@ -236,7 +281,7 @@ export default function BecomeBuilderPage() {
tags,
});
- toast({ title: 'Builder profile created!', description: 'Your profile has been published.' });
+ toast({ title: `Builder profile ${existingProfile ? 'updated' : 'created'}!`, description: 'Your profile has been published.' });
navigate(`/coach/${user?.pubkey}/${identifier}`);
} catch (error) {
toast({ title: 'Failed to publish', description: error instanceof Error ? error.message : 'Error', variant: 'destructive' });
@@ -345,8 +390,6 @@ export default function BecomeBuilderPage() {
Tell the scene what you build and how you work
-
-
@@ -355,6 +398,21 @@ export default function BecomeBuilderPage() {