Add currency selection to user profile settings (#41)
This commit is contained in:
parent
0f66ab7478
commit
700f9325a3
|
|
@ -27,6 +27,7 @@ class ProfileUpdateRequest extends FormRequest
|
|||
'max:255',
|
||||
Rule::unique(User::class)->ignore($this->user()->id),
|
||||
],
|
||||
'currency_code' => ['required', 'string', 'max:3', Rule::in(['USD', 'EUR', 'GBP', 'JPY', 'CHF', 'CAD', 'AUD', 'CNY', 'INR', 'MXN'])],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class User extends Authenticatable
|
|||
'password',
|
||||
'encryption_salt',
|
||||
'onboarded_at',
|
||||
'currency_code',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class UserFactory extends Factory
|
|||
return [
|
||||
'name' => fake()->name(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'currency_code' => 'USD',
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= 'password',
|
||||
'remember_token' => Str::random(10),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('currency_code', 3)->default('USD')->after('email');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('currency_code');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -8,6 +8,13 @@ import { Badge } from '@/components/ui/badge';
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { useTwoFactorAuth } from '@/hooks/use-two-factor-auth';
|
||||
import AppLayout from '@/layouts/app-layout';
|
||||
|
|
@ -16,6 +23,7 @@ import { edit as accountEdit } from '@/routes/account';
|
|||
import { disable, enable } from '@/routes/two-factor';
|
||||
import { send } from '@/routes/verification';
|
||||
import { type BreadcrumbItem, type SharedData } from '@/types';
|
||||
import { CURRENCY_OPTIONS } from '@/types/account';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import { Form, Head, Link, usePage } from '@inertiajs/react';
|
||||
import { ShieldBan, ShieldCheck } from 'lucide-react';
|
||||
|
|
@ -114,6 +122,39 @@ export default function Account({
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="currency_code">
|
||||
Currency
|
||||
</Label>
|
||||
|
||||
<Select
|
||||
name="currency_code"
|
||||
defaultValue={auth.user.currency_code}
|
||||
required
|
||||
>
|
||||
<SelectTrigger className="mt-1 w-full">
|
||||
<SelectValue placeholder="Select currency" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{CURRENCY_OPTIONS.map(
|
||||
(currency) => (
|
||||
<SelectItem
|
||||
key={currency}
|
||||
value={currency}
|
||||
>
|
||||
{currency}
|
||||
</SelectItem>
|
||||
),
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<InputError
|
||||
className="mt-2"
|
||||
message={errors.currency_code}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{mustVerifyEmail &&
|
||||
auth.user.email_verified_at === null && (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { InertiaLinkProps } from '@inertiajs/react';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
import { ReactNode } from 'react';
|
||||
import { CurrencyCode } from './account';
|
||||
import { PricingConfig } from './pricing';
|
||||
import { UUID } from './uuid';
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ export interface User {
|
|||
id: UUID;
|
||||
name: string;
|
||||
email: string;
|
||||
currency_code: CurrencyCode;
|
||||
avatar?: string;
|
||||
email_verified_at: string | null;
|
||||
two_factor_enabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ test('profile information can be updated', function () {
|
|||
->patch(route('profile.update'), [
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
'currency_code' => 'EUR',
|
||||
]);
|
||||
|
||||
$response
|
||||
|
|
@ -31,6 +32,7 @@ test('profile information can be updated', function () {
|
|||
expect($user->name)->toBe('Test User');
|
||||
expect($user->email)->toBe('test@example.com');
|
||||
expect($user->email_verified_at)->toBeNull();
|
||||
expect($user->currency_code)->toBe('EUR');
|
||||
});
|
||||
|
||||
test('email verification status is unchanged when the email address is unchanged', function () {
|
||||
|
|
@ -41,6 +43,7 @@ test('email verification status is unchanged when the email address is unchanged
|
|||
->patch(route('profile.update'), [
|
||||
'name' => 'Test User',
|
||||
'email' => $user->email,
|
||||
'currency_code' => $user->currency_code,
|
||||
]);
|
||||
|
||||
$response
|
||||
|
|
|
|||
Loading…
Reference in New Issue