Align external preview UX and unlock leads preview flow

This commit is contained in:
Tracewebstudio Dev 2026-04-15 00:15:22 +02:00
parent df5326db73
commit 3265b1a16a

View file

@ -560,8 +560,6 @@ function portfolioMediaConfig(roleKey: string): {
|| normalized === 'GRAPHIC_DESIGNER' || normalized === 'GRAPHIC_DESIGNER'
|| normalized === 'SOCIAL_MEDIA_MANAGER' || normalized === 'SOCIAL_MEDIA_MANAGER'
|| normalized === 'CATERING_SERVICES' || normalized === 'CATERING_SERVICES'
|| normalized === 'DEVELOPER'
|| normalized === 'FITNESS_TRAINER'
) { ) {
return { return {
mode: 'visual', mode: 'visual',
@ -1622,6 +1620,7 @@ export default function DashboardDesignPreview(props: {
const serviceTabKey = normalizeTabKey(spec.serviceTabLabel); const serviceTabKey = normalizeTabKey(spec.serviceTabLabel);
const galleryTabKey = normalizeTabKey(spec.galleryTabLabel); const galleryTabKey = normalizeTabKey(spec.galleryTabLabel);
const experienceTabKey = normalizeTabKey(spec.experienceTabLabel); const experienceTabKey = normalizeTabKey(spec.experienceTabLabel);
const requiresVisualAssets = mediaConfig.mode === 'visual';
const testimonialsTabKey = normalizeTabKey('testimonials'); const testimonialsTabKey = normalizeTabKey('testimonials');
const faqsTabKey = normalizeTabKey('faqs'); const faqsTabKey = normalizeTabKey('faqs');
const portfolioJobsCompleted = portfolioJobsCompletedPreview; const portfolioJobsCompleted = portfolioJobsCompletedPreview;
@ -1708,7 +1707,7 @@ export default function DashboardDesignPreview(props: {
}); });
if (stepKey === serviceTabKey && portfolioServices().length < 1) { if (stepKey === serviceTabKey && portfolioServices().length < 1) {
setPortfolioValidationNotice('Add at least one service with pricing.'); setPortfolioValidationNotice('Add at least one service with pricing.');
} else if (stepKey === galleryTabKey && (portfolioPhotos().length < 1 || portfolioPhotos().length > 6)) { } else if (stepKey === galleryTabKey && requiresVisualAssets && (portfolioPhotos().length < 1 || portfolioPhotos().length > 6)) {
setPortfolioValidationNotice('Add 1 to 6 portfolio photos.'); setPortfolioValidationNotice('Add 1 to 6 portfolio photos.');
} else if (stepKey === experienceTabKey && portfolioExperiences().length < 1) { } else if (stepKey === experienceTabKey && portfolioExperiences().length < 1) {
setPortfolioValidationNotice('Add at least one experience entry.'); setPortfolioValidationNotice('Add at least one experience entry.');
@ -1720,7 +1719,7 @@ export default function DashboardDesignPreview(props: {
setPortfolioFormErrors((prev) => ({ ...prev, ...nextErrors })); setPortfolioFormErrors((prev) => ({ ...prev, ...nextErrors }));
return Object.keys(nextErrors).length === 0 return Object.keys(nextErrors).length === 0
&& !(stepKey === serviceTabKey && portfolioServices().length < 1) && !(stepKey === serviceTabKey && portfolioServices().length < 1)
&& !(stepKey === galleryTabKey && (portfolioPhotos().length < 1 || portfolioPhotos().length > 6)) && !(stepKey === galleryTabKey && requiresVisualAssets && (portfolioPhotos().length < 1 || portfolioPhotos().length > 6))
&& !(stepKey === experienceTabKey && portfolioExperiences().length < 1); && !(stepKey === experienceTabKey && portfolioExperiences().length < 1);
}; };
const addServiceDraft = () => { const addServiceDraft = () => {
@ -1901,18 +1900,36 @@ export default function DashboardDesignPreview(props: {
<Show when={selectedPortfolioTabKey === galleryTabKey}> <Show when={selectedPortfolioTabKey === galleryTabKey}>
<div style="display:grid;gap:10px;margin-top:10px"> <div style="display:grid;gap:10px;margin-top:10px">
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px"> <Show
<p style="margin:0;font-size:12px;color:#374151">Portfolio photos ({portfolioPhotos().length}/6)</p> when={requiresVisualAssets}
<button type="button" onClick={addPhotoItem} disabled={portfolioPhotos().length >= 6} style={`height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:${portfolioPhotos().length >= 6 ? 'not-allowed' : 'pointer'};opacity:${portfolioPhotos().length >= 6 ? 0.6 : 1}`}>Add Photo</button> fallback={
</div> <div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;display:grid;gap:8px">
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px"> <p style="margin:0;font-size:12px;color:#374151;font-weight:600">Structured work proof (photos optional)</p>
<For each={portfolioPhotos()}>{(photo, idx) => ( <For each={mediaConfig.items}>{(item, idx) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#FAFBFD;padding:10px;display:flex;align-items:center;justify-content:space-between;gap:8px"> <div style="border:1px solid #E5E7EB;border-radius:8px;background:white;padding:8px 10px;display:flex;align-items:flex-start;gap:8px">
<span style="font-size:12px;font-weight:600;color:#374151">{photo}</span> <FileText size={14} style="color:#9CA3AF;flex-shrink:0;margin-top:2px" />
<button type="button" onClick={() => removePhotoItem(idx())} style="height:26px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 8px;font-size:11px;font-weight:700;color:#374151;cursor:pointer">Remove</button> <div>
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{item}</p>
<p style="margin:4px 0 0;font-size:11px;color:#6B7280">Entry #{idx() + 1} for outcome-focused portfolio evidence.</p>
</div>
</div>
)}</For>
</div> </div>
)}</For> }
</div> >
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px">
<p style="margin:0;font-size:12px;color:#374151">Portfolio photos ({portfolioPhotos().length}/6)</p>
<button type="button" onClick={addPhotoItem} disabled={portfolioPhotos().length >= 6} style={`height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:${portfolioPhotos().length >= 6 ? 'not-allowed' : 'pointer'};opacity:${portfolioPhotos().length >= 6 ? 0.6 : 1}`}>Add Photo</button>
</div>
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px">
<For each={portfolioPhotos()}>{(photo, idx) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#FAFBFD;padding:10px;display:flex;align-items:center;justify-content:space-between;gap:8px">
<span style="font-size:12px;font-weight:600;color:#374151">{photo}</span>
<button type="button" onClick={() => removePhotoItem(idx())} style="height:26px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 8px;font-size:11px;font-weight:700;color:#374151;cursor:pointer">Remove</button>
</div>
)}</For>
</div>
</Show>
</div> </div>
</Show> </Show>
@ -2853,7 +2870,8 @@ export default function DashboardDesignPreview(props: {
} }
if (customerKey() === 'leads') { if (customerKey() === 'leads') {
if (!bothApprovalsApproved()) { const lockLeadsPreview = false;
if (lockLeadsPreview && !bothApprovalsApproved()) {
return ( return (
<div style="display:grid;gap:12px"> <div style="display:grid;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px"> <div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">