2025-10-26 00:02:19 -03:00
<!-- Riot.js component for the profile form (converted from app/settings/profile - form.tsx) -->
< template >
< div class = "space-y-4" >
< controller name = "username" >
< div class = "mb-4" >
< label class = "block text-sm font-medium mb-1" > Username< / label >
2025-11-15 21:52:53 -03:00
< input class = "w-full p-2 border rounded {errors.username ? 'border-red-500' : 'border-gray-300'}"
2025-10-26 00:02:19 -03:00
bind="{username}"
placeholder="Enter username" />
2025-11-15 21:52:53 -03:00
{errors.username & & < p class = "text-red-500 text-xs mt-1" > {errors.username.message}< / p > }
2025-10-26 00:02:19 -03:00
< p class = "text-sm text-gray-500 mt-1" >
This is your public display name. It can be your real name or a pseudonym. You can only change this once every 30 days.
< / p >
< / div >
< / controller >
< controller name = "email" >
< div class = "mb-4" >
< label class = "block text-sm font-medium mb-1" > Email< / label >
< input type = "email"
2025-11-15 21:52:53 -03:00
class="w-full p-2 border rounded {errors.email ? 'border-red-500' : 'border-gray-300'}"
2025-10-26 00:02:19 -03:00
bind="{email}"
placeholder="Enter email" />
2025-11-15 21:52:53 -03:00
{errors.email & & < p class = "text-red-500 text-xs mt-1" > {errors.email.message}< / p > }
2025-10-26 00:02:19 -03:00
< p class = "text-sm text-gray-500 mt-1" >
You can manage verified email addresses in your email settings.
< / p >
< / div >
< / controller >
< controller name = "bio" >
< div class = "mb-4" >
< label class = "block text-sm font-medium mb-1" > Bio< / label >
2025-11-15 21:52:53 -03:00
< textarea class = "w-full p-2 border rounded {errors.bio ? 'border-red-500' : 'border-gray-300'}"
2025-10-26 00:02:19 -03:00
bind="{bio}"
rows="4"
placeholder="Tell us a little bit about yourself">< / textarea >
2025-11-15 21:52:53 -03:00
{errors.bio & & < p class = "text-red-500 text-xs mt-1" > {errors.bio.message}< / p > }
2025-10-26 00:02:19 -03:00
< p class = "text-sm text-gray-500 mt-1" >
You can @mention other users and organizations to link to them.
< / p >
< / div >
< / controller >
< button class = "bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
@click="{handleSubmit(onSubmit)}">
Update profile
< / button >
< / div >
< / template >
2025-10-26 08:07:14 -03:00
< script >
2025-10-26 00:02:19 -03:00
import { useState } from 'riot';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import './style.css';
export default {
// Reactive state
2025-11-15 21:52:53 -03:00
data() {
return {
username: '',
email: '',
bio: '',
errors: {
username: null,
email: null,
bio: null
}
}
},
2025-10-26 00:02:19 -03:00
// Validation schema
schema: z.object({
username: z.string().min(2, { message: "Username must be at least 2 characters." }).max(30, { message: "Username must not be longer than 30 characters." }),
email: z.string().email(),
bio: z.string().min(4).max(160)
}),
// Methods
handleSubmit(callback) {
const result = this.schema.safeParse({
username: this.username,
email: this.email,
bio: this.bio
});
2025-11-15 21:52:53 -03:00
// Clear previous errors
this.errors = {
username: null,
email: null,
bio: null
};
2025-10-26 00:02:19 -03:00
if (result.success) {
callback(result.data);
} else {
2025-11-15 21:52:53 -03:00
result.error.errors.forEach(err => {
this.errors[err.path[0]] = err;
});
2025-10-26 00:02:19 -03:00
}
},
onSubmit(data) {
console.log(JSON.stringify(data, null, 2));
}
};
< / script >