monacousa-portal/pages/auth/signup-mockup.vue

747 lines
16 KiB
Vue

<template>
<div class="auth-page">
<div class="auth-container auth-container--wide">
<!-- Progress Bar -->
<div class="progress-bar">
<div
class="progress-bar__fill"
:style="{ width: `${(step / 3) * 100}%` }"
></div>
</div>
<!-- Step 1: Account Info -->
<div
v-if="step === 1"
v-motion
:initial="{ opacity: 0, x: 50 }"
:enter="{ opacity: 1, x: 0 }"
class="signup-step"
>
<div class="auth-logo">
<img src="/MONACOUSA-Flags_376x376.png" alt="MonacoUSA" class="logo" />
<h1>MonacoUSA Portal</h1>
</div>
<div class="auth-header">
<h2>Create Your Account</h2>
<p>Join Monaco's premier business community</p>
</div>
<form class="auth-form" @submit.prevent="nextStep">
<div class="form-row">
<FloatingInput
v-model="form.firstName"
label="First Name"
variant="glass"
leftIcon="user"
required
/>
<FloatingInput
v-model="form.lastName"
label="Last Name"
variant="glass"
leftIcon="user"
required
/>
</div>
<FloatingInput
v-model="form.email"
label="Email Address"
type="email"
variant="glass"
leftIcon="mail"
helperText="We'll use this for account notifications"
required
/>
<FloatingInput
v-model="form.password"
label="Password"
type="password"
variant="glass"
leftIcon="lock"
helperText="Minimum 8 characters with uppercase and number"
required
/>
<FloatingInput
v-model="form.confirmPassword"
label="Confirm Password"
type="password"
variant="glass"
leftIcon="lock"
:error="passwordError"
required
/>
<div class="password-strength">
<span class="password-strength__label">Password Strength:</span>
<div class="password-strength__bars">
<span
v-for="i in 4"
:key="i"
class="password-strength__bar"
:class="{ 'password-strength__bar--filled': i <= passwordStrength }"
></span>
</div>
<span class="password-strength__text">{{ passwordStrengthText }}</span>
</div>
<MonacoButton
type="submit"
variant="primary"
size="lg"
block
>
Continue to Profile
</MonacoButton>
</form>
<div class="auth-footer">
<p>Already have an account? <a href="/auth/login" class="link">Sign in</a></p>
</div>
</div>
<!-- Step 2: Profile Info -->
<div
v-if="step === 2"
v-motion
:initial="{ opacity: 0, x: 50 }"
:enter="{ opacity: 1, x: 0 }"
class="signup-step"
>
<div class="step-header">
<button @click="previousStep" class="back-button">
<Icon name="arrow-left" />
Back
</button>
<h2>Professional Information</h2>
</div>
<form class="auth-form" @submit.prevent="nextStep">
<FloatingInput
v-model="form.company"
label="Company Name"
variant="glass"
leftIcon="building"
required
/>
<FloatingInput
v-model="form.title"
label="Job Title"
variant="glass"
leftIcon="briefcase"
required
/>
<div class="form-row">
<FloatingInput
v-model="form.phone"
label="Phone Number"
type="tel"
variant="glass"
leftIcon="phone"
required
/>
<FloatingInput
v-model="form.linkedin"
label="LinkedIn Profile"
variant="glass"
leftIcon="link"
helperText="Optional"
/>
</div>
<div class="form-group">
<label class="form-label">Industry</label>
<select v-model="form.industry" class="form-select">
<option value="">Select your industry</option>
<option value="finance">Finance & Banking</option>
<option value="tech">Technology</option>
<option value="realestate">Real Estate</option>
<option value="hospitality">Hospitality</option>
<option value="retail">Retail & Luxury</option>
<option value="consulting">Consulting</option>
<option value="legal">Legal Services</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Bio</label>
<textarea
v-model="form.bio"
class="form-textarea"
placeholder="Tell us about yourself and your business interests..."
rows="4"
></textarea>
</div>
<MonacoButton
type="submit"
variant="primary"
size="lg"
block
>
Continue to Membership
</MonacoButton>
</form>
</div>
<!-- Step 3: Membership -->
<div
v-if="step === 3"
v-motion
:initial="{ opacity: 0, x: 50 }"
:enter="{ opacity: 1, x: 0 }"
class="signup-step"
>
<div class="step-header">
<button @click="previousStep" class="back-button">
<Icon name="arrow-left" />
Back
</button>
<h2>Choose Your Membership</h2>
</div>
<div class="membership-plans">
<div
v-for="plan in membershipPlans"
:key="plan.id"
class="plan-card"
:class="{ 'plan-card--selected': form.membershipPlan === plan.id }"
@click="form.membershipPlan = plan.id"
>
<div class="plan-card__header">
<h3 class="plan-card__name">{{ plan.name }}</h3>
<span class="plan-card__price">${{ plan.price }}/year</span>
</div>
<ul class="plan-card__features">
<li v-for="feature in plan.features" :key="feature">
<Icon name="check" />
{{ feature }}
</li>
</ul>
<span v-if="plan.popular" class="plan-card__badge">Most Popular</span>
</div>
</div>
<div class="terms-section">
<label class="checkbox-label">
<input type="checkbox" v-model="form.agreeTerms" />
<span>
I agree to the <a href="/terms" class="link">Terms of Service</a>
and <a href="/privacy" class="link">Privacy Policy</a>
</span>
</label>
<label class="checkbox-label">
<input type="checkbox" v-model="form.agreeNewsletter" />
<span>Send me updates about events and opportunities</span>
</label>
</div>
<MonacoButton
variant="primary"
size="lg"
block
:disabled="!form.agreeTerms || !form.membershipPlan"
@click="handleSignup"
>
Complete Registration
</MonacoButton>
</div>
<!-- Success State -->
<div
v-if="step === 4"
v-motion
:initial="{ opacity: 0, scale: 0.9 }"
:enter="{ opacity: 1, scale: 1 }"
class="success-state"
>
<div class="success-icon">🎉</div>
<h2>Welcome to MonacoUSA!</h2>
<p>Your account has been created successfully.</p>
<p>Please check your email to verify your account.</p>
<MonacoButton variant="primary" size="lg" @click="goToLogin">
Go to Login
</MonacoButton>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import FloatingInput from '~/components/ui/FloatingInput.vue'
import MonacoButton from '~/components/ui/MonacoButton.vue'
import Icon from '~/components/ui/Icon.vue'
const step = ref(1)
const form = ref({
// Step 1
firstName: '',
lastName: '',
email: '',
password: '',
confirmPassword: '',
// Step 2
company: '',
title: '',
phone: '',
linkedin: '',
industry: '',
bio: '',
// Step 3
membershipPlan: '',
agreeTerms: false,
agreeNewsletter: true
})
const membershipPlans = [
{
id: 'basic',
name: 'Basic',
price: 250,
features: [
'Access to member directory',
'Monthly newsletter',
'Event invitations',
'Basic networking features'
]
},
{
id: 'professional',
name: 'Professional',
price: 500,
popular: true,
features: [
'Everything in Basic',
'Priority event registration',
'Enhanced profile features',
'Business matchmaking',
'Quarterly exclusive events'
]
},
{
id: 'executive',
name: 'Executive',
price: 1000,
features: [
'Everything in Professional',
'VIP event access',
'Personal concierge service',
'Board meeting participation',
'Guest passes (5/year)',
'Premium networking tools'
]
}
]
const passwordError = computed(() => {
if (form.value.confirmPassword && form.value.password !== form.value.confirmPassword) {
return 'Passwords do not match'
}
return ''
})
const passwordStrength = computed(() => {
const password = form.value.password
if (!password) return 0
let strength = 0
if (password.length >= 8) strength++
if (/[A-Z]/.test(password)) strength++
if (/[0-9]/.test(password)) strength++
if (/[^A-Za-z0-9]/.test(password)) strength++
return strength
})
const passwordStrengthText = computed(() => {
const texts = ['', 'Weak', 'Fair', 'Good', 'Strong']
return texts[passwordStrength.value]
})
const nextStep = () => {
step.value++
}
const previousStep = () => {
step.value--
}
const handleSignup = () => {
console.log('Signup with:', form.value)
step.value = 4
}
const goToLogin = () => {
window.location.href = '/auth/login'
}
</script>
<style scoped lang="scss">
.auth-page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #fef2f2 0%, #ffffff 100%);
padding: 2rem;
}
.auth-container {
max-width: 500px;
width: 100%;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1);
overflow: hidden;
&--wide {
max-width: 800px;
}
}
.progress-bar {
height: 4px;
background: rgba(220, 38, 38, 0.1);
&__fill {
height: 100%;
background: linear-gradient(90deg, #dc2626 0%, #b91c1c 100%);
transition: width 0.3s ease;
}
}
.signup-step {
padding: 3rem;
}
.auth-logo {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 2rem;
img {
width: 48px;
height: 48px;
}
h1 {
margin: 0;
font-size: 1.5rem;
font-weight: 700;
color: #dc2626;
}
}
.auth-header {
margin-bottom: 2rem;
h2 {
margin: 0 0 0.5rem;
font-size: 2rem;
font-weight: 700;
color: #27272a;
}
p {
margin: 0;
color: #6b7280;
}
}
.step-header {
margin-bottom: 2rem;
h2 {
margin: 0.5rem 0 0;
font-size: 1.5rem;
font-weight: 700;
color: #27272a;
}
}
.back-button {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0;
background: none;
border: none;
color: #6b7280;
font-size: 0.875rem;
cursor: pointer;
transition: color 0.2s;
&:hover {
color: #dc2626;
}
}
.auth-form {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.form-label {
font-size: 0.875rem;
font-weight: 500;
color: #27272a;
}
.form-select,
.form-textarea {
padding: 0.75rem 1rem;
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(20px);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
font-size: 1rem;
color: #27272a;
transition: all 0.2s;
&:focus {
outline: none;
border-color: #dc2626;
box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.1);
}
}
.form-textarea {
resize: vertical;
min-height: 100px;
font-family: inherit;
}
.password-strength {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem;
background: rgba(220, 38, 38, 0.05);
border-radius: 8px;
&__label {
font-size: 0.875rem;
color: #6b7280;
}
&__bars {
display: flex;
gap: 0.25rem;
flex: 1;
}
&__bar {
height: 4px;
flex: 1;
background: #e5e5e5;
border-radius: 2px;
transition: background 0.3s;
&--filled {
background: #dc2626;
}
}
&__text {
font-size: 0.875rem;
font-weight: 500;
color: #dc2626;
}
}
.membership-plans {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-bottom: 2rem;
}
.plan-card {
position: relative;
padding: 1.5rem;
background: white;
border: 2px solid #e5e5e5;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s;
&:hover {
border-color: #dc2626;
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
&--selected {
border-color: #dc2626;
background: rgba(220, 38, 38, 0.05);
}
&__header {
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid #e5e5e5;
}
&__name {
margin: 0 0 0.5rem;
font-size: 1.125rem;
font-weight: 600;
color: #27272a;
}
&__price {
font-size: 1.5rem;
font-weight: 700;
color: #dc2626;
}
&__features {
list-style: none;
padding: 0;
margin: 0;
li {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
font-size: 0.875rem;
color: #6b7280;
svg {
width: 1rem;
height: 1rem;
color: #10b981;
flex-shrink: 0;
}
}
}
&__badge {
position: absolute;
top: -0.5rem;
right: 1rem;
padding: 0.25rem 0.75rem;
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
color: white;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
}
}
.terms-section {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 2rem;
}
.checkbox-label {
display: flex;
align-items: flex-start;
gap: 0.5rem;
cursor: pointer;
input[type="checkbox"] {
margin-top: 0.125rem;
width: 1.25rem;
height: 1.25rem;
accent-color: #dc2626;
cursor: pointer;
flex-shrink: 0;
}
span {
font-size: 0.875rem;
color: #6b7280;
line-height: 1.5;
}
}
.link {
color: #dc2626;
text-decoration: none;
font-weight: 500;
&:hover {
text-decoration: underline;
}
}
.auth-footer {
margin-top: 2rem;
text-align: center;
p {
margin: 0;
font-size: 0.875rem;
color: #6b7280;
}
}
.success-state {
padding: 4rem;
text-align: center;
.success-icon {
font-size: 4rem;
margin-bottom: 1rem;
}
h2 {
margin: 0 0 1rem;
font-size: 2rem;
font-weight: 700;
color: #27272a;
}
p {
margin: 0 0 0.5rem;
color: #6b7280;
&:last-of-type {
margin-bottom: 2rem;
}
}
}
// Responsive
@media (max-width: 768px) {
.membership-plans {
grid-template-columns: 1fr;
}
.form-row {
grid-template-columns: 1fr;
}
.signup-step {
padding: 2rem;
}
}
</style>