ghostguild-org/app/components/CirclePicker.vue
Jennie Robinson Faber 7292b11c0b feat(member): account/profile polish + tier upgrade flow
- Timezone: curated USelectMenu dropdown (app/config/timezones.js), preserves unknown saved values
- Profile save now uses useToast() for success/error; remove inline save banner
- Nav onboarding dot nudged down 1px for optical alignment with lowercase text
- Onboarding: skip a suggestion with POST /api/onboarding/track {skip}; member.onboarding.skipped map; does not affect graduation
- CirclePicker takes :saved-value so 'Current' badge stays until save completes
- PrivacyToggle is binary (USwitch labeled Private); member schema enum reduced to ['members','private']; zod coerces legacy 'public'
- New /member/payment-setup page: HelcimPay $0 verify + update-contribution, wired from account.vue via requiresPaymentSetup redirect
- Helcim portal: NUXT_PUBLIC_HELCIM_PORTAL_URL env + account.vue 'Manage billing in Helcim' link
- Migration script: scripts/migrate-privacy-public-to-members.js
2026-04-14 20:35:37 +01:00

100 lines
2.2 KiB
Vue

<template>
<div class="circle-picker">
<div
v-for="circle in circles"
:key="circle.value"
class="circle-option"
:class="{
selected: modelValue === circle.value,
current: savedValue === circle.value,
}"
@click="$emit('update:modelValue', circle.value)"
>
<span class="circle-name">{{ circle.label }}</span>
<span class="circle-desc">{{ circle.description }}</span>
<span
v-if="savedValue === circle.value"
class="circle-tag"
:style="{ color: `var(--c-${circle.value})`, borderColor: `var(--c-${circle.value})` }"
>Current</span>
</div>
</div>
</template>
<script setup>
defineProps({
modelValue: { type: String, default: '' },
savedValue: { type: String, default: '' },
circles: {
type: Array,
default: () => [
{ value: 'community', label: 'Community', description: 'Learning together, exploring cooperative models' },
{ value: 'founder', label: 'Founder', description: 'Actively building a cooperative studio' },
{ value: 'practitioner', label: 'Practitioner', description: 'Experienced in cooperative practice' },
],
},
})
defineEmits(['update:modelValue'])
</script>
<style scoped>
.circle-picker {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 10px;
margin-bottom: 12px;
}
.circle-option {
border: 1px dashed var(--border);
padding: 14px 12px;
background: var(--bg);
cursor: pointer;
transition: all 0.15s;
}
.circle-option:hover {
background: var(--surface-hover);
}
.circle-option.selected {
border-color: var(--candle);
border-style: solid;
background: var(--surface);
}
.circle-name {
font-size: 13px;
font-weight: 600;
display: block;
margin-bottom: 4px;
}
.circle-option.selected .circle-name {
color: var(--candle);
}
.circle-desc {
font-size: 11px;
color: var(--text-faint);
line-height: 1.5;
display: block;
}
.circle-tag {
font-size: 9px;
letter-spacing: 0.06em;
text-transform: uppercase;
margin-top: 6px;
display: inline-block;
padding: 1px 6px;
border: 1px dashed;
}
@media (max-width: 768px) {
.circle-picker {
grid-template-columns: 1fr;
}
}
</style>