Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support registering through SPA prototype #505

Merged
merged 1 commit into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions app/Http/Controllers/Api/CurrencyController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\CurrencyResource;
use App\Models\Currency;

class CurrencyController extends Controller
{
public function index()
{
return CurrencyResource::collection(Currency::all());
}
}
50 changes: 50 additions & 0 deletions app/Http/Controllers/Api/RegisterController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace App\Http\Controllers\Api;

use App\Actions\SendVerificationMailAction;
use App\Http\Controllers\Controller;
use App\Models\Space;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class RegisterController extends Controller
{
public function __invoke(Request $request)
{
if (config('app.disable_registration')) {
abort(404);
}

$request->validate([
'name' => ['required'],
'email' => ['required', 'email', 'unique:users'],
'password' => ['required', 'confirmed'],
'currency' => ['required', 'exists:currencies,id'],
]);

$user = User::query()
->create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => Hash::make($request->input('password')),
'verification_token' => Str::random(100),
]);

$space = Space::query()
->create([
'currency_id' => $request->input('currency'),
'name' => $user->name . '\'s Space',
]);

$user->spaces()->attach($space->id, ['role' => 'admin']);

(new SendVerificationMailAction())->execute($user->id);

return [
'success' => true,
];
}
}
19 changes: 19 additions & 0 deletions app/Http/Resources/CurrencyResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class CurrencyResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'symbol' => $this->symbol,
'iso' => $this->iso,
];
}
}
5 changes: 5 additions & 0 deletions resources/assets/js/prototype/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import translations from './translations';
import App from './components/App.vue';

import Login from './screens/Login.vue';
import Register from './screens/Register.vue';
import Dashboard from './screens/Dashboard.vue';
import TransactionsIndex from './screens/Transactions/Index.vue';
import TransactionsCreate from './screens/Transactions/Create.vue';
Expand All @@ -27,6 +28,10 @@ const routes = [
path: '/prototype/login',
name: 'login',
component: Login,
}, {
path: '/prototype/register',
name: 'register',
component: Register,
}, {
path: '/prototype/dashboard',
name: 'dashboard',
Expand Down
4 changes: 3 additions & 1 deletion resources/assets/js/prototype/screens/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ watch(showError, value => {
</div>
</button>
</div>
<div class="mt-5 text-sm text-center dark:text-white">{{ versionNumber }}</div>
<div class="mt-4 text-sm text-center">
<router-link class="text-gray-500 dark:text-white" :to="{ name: 'register' }">First time here? Register.</router-link>
</div>
</div>
<div v-if="showError" class="absolute top-0 left-0 right-0 flex">
<div class="mt-10 mx-auto py-3 px-5 flex bg-white border border-gray-200 rounded-lg shadow-sm">
Expand Down
96 changes: 96 additions & 0 deletions resources/assets/js/prototype/screens/Register.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script setup>
import axios from 'axios';
import { Loader2 } from 'lucide-vue';
import { getCurrentInstance, ref } from 'vue';

const router = getCurrentInstance().proxy.$router;

const isBusy = ref(false);
const errors = ref({});
const name = ref('');
const email = ref('');
const password = ref('');
const repeatedPassword = ref('');
const currencies = ref([]);
const currency = ref(1);

const fetchCurrencies = () => {
axios
.get('/api/currencies')
.then(response => {
currencies.value = response.data;
});
};

const register = () => {
isBusy.value = true;

axios
.post('/api/register', { name: name.value, email: email.value, password: password.value, password_confirmation: repeatedPassword.value, currency: currency.value })
.then(response => {
const json = response.data;

if (json.success) {
router.push({ name: 'login' });
}
})
.catch(error => {
isBusy.value = false;
password.value = '';
repeatedPassword.value = '';

if (error.response && error.response.data) {
const json = error.response.data;

if (json.errors) {
errors.value = json.errors;
}
}
});
};

fetchCurrencies();
</script>

<template>
<div class="flex items-center justify-center min-h-screen">
<div class="flex-1 max-w-sm">
<div class="p-5 space-y-5 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg">
<div>
<label class="block mb-2 text-sm dark:text-white">{{ $t('name') }}</label>
<input class="w-full px-3.5 py-2.5 text-sm dark:text-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg" type="text" v-model="name" @keyup.enter="register" />
<div v-if="errors.name" class="mt-1.5 text-sm text-red-500">{{ errors.name[0] }}</div>
</div>
<div>
<label class="block mb-2 text-sm dark:text-white">{{ $t('email') }}</label>
<input class="w-full px-3.5 py-2.5 text-sm dark:text-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg" type="email" v-model="email" @keyup.enter="register" />
<div v-if="errors.email" class="mt-1.5 text-sm text-red-500">{{ errors.email[0] }}</div>
</div>
<div>
<label class="block mb-2 text-sm dark:text-white">{{ $t('password') }}</label>
<input class="w-full px-3.5 py-2.5 text-sm dark:text-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg" type="password" v-model="password" @keyup.enter="register" />
<div v-if="errors.password" class="mt-1.5 text-sm text-red-500">{{ errors.password[0] }}</div>
</div>
<div>
<label class="block mb-2 text-sm dark:text-white">{{ $t('repeatPassword') }}</label>
<input class="w-full px-3.5 py-2.5 text-sm dark:text-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg" type="password" v-model="repeatedPassword" @keyup.enter="register" />
</div>
<div>
<label class="block mb-2 text-sm dark:text-white">{{ $t('currency') }}</label>
<select class="w-full px-3.5 py-2.5 text-sm dark:text-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg appearance-none" v-model="currency">
<option v-for="currency in currencies" :value="currency.id">{{ currency.name }} (<span v-html="currency.symbol"></span>)</option>
</select>
</div>
<button class="w-full py-3 text-sm text-white bg-gray-900 dark:bg-gray-950 rounded-lg" @click="register">
<span v-if="!isBusy">{{ $t('register') }}</span>
<div v-if="isBusy" class="flex justify-center h-5">
<Loader2 class="animate-spin" :size="18" :strokeWidth="2.4" />
</div>
</button>
</div>
<div class="mt-4 text-sm text-center">
<router-link class="text-gray-500 dark:text-white" :to="{ name: 'login' }">Already using Budget? Log in.</router-link>
</div>
</div>
</div>
</template>
4 changes: 4 additions & 0 deletions resources/assets/js/prototype/translations/de.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"amount": "Betrag",
"create": "Erstellen",
"currency": "Währung",
"dailyBalanceGraphDescription": "Hier ist dein Kontostand im Laufe des Monats",
"dashboard": "Dashboard",
"date": "Datum",
Expand All @@ -13,8 +14,11 @@
"goodMorning": "Guten Morgen",
"language": "Sprache",
"logIn": "Anmelden",
"name": "Name",
"password": "Passwort",
"recurringDescription": "Dies ist eine wiederkehrende Transaktion—erstelle sie auch in Zukunft für mich",
"register": "Registriere",
"repeatPassword": "Passwort wiederholen",
"spending": "Ausgabe",
"spendingDescriptionPlaceholder": "Geburtstagsgeschenk für Angela",
"tag": "Schlagwort",
Expand Down
4 changes: 4 additions & 0 deletions resources/assets/js/prototype/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"amount": "Amount",
"create": "Create",
"currency": "Currency",
"dailyBalanceGraphDescription": "Here is your balance throughout the month",
"dashboard": "Dashboard",
"date": "Date",
Expand All @@ -13,8 +14,11 @@
"goodMorning": "Good morning",
"language": "Language",
"logIn": "Log in",
"name": "Name",
"password": "Password",
"recurringDescription": "This is a recurring transaction—create it for me in the future",
"register": "Register",
"repeatPassword": "Repeat password",
"spending": "Spending",
"spendingDescriptionPlaceholder": "Birthday present for Angela",
"tag": "Tag",
Expand Down
4 changes: 4 additions & 0 deletions resources/assets/js/prototype/translations/nl.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"amount": "Bedrag",
"create": "Creëer",
"currency": "Valuta",
"dailyBalanceGraphDescription": "Dit is je balans gedurende deze maand",
"dashboard": "Dashboard",
"date": "Datum",
Expand All @@ -13,8 +14,11 @@
"goodMorning": "Goedemorgen",
"language": "Taal",
"logIn": "Log in",
"name": "Naam",
"password": "Wachtwoord",
"recurringDescription": "Dit is een terugkerende transactie–maak deze in de toekomst voor mij aan",
"register": "Registreer",
"repeatPassword": "Herhaal wachtwoord",
"spending": "Uitgave",
"spendingDescriptionPlaceholder": "Verjaardagscadeau voor Angela",
"tag": "Etiket",
Expand Down
4 changes: 4 additions & 0 deletions resources/assets/js/prototype/translations/ru.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"amount": "Сумма",
"create": "Создать",
"currency": "Валюта",
"dailyBalanceGraphDescription": "Здесь отображается ваш баланс в течение месяца",
"dashboard": "Панель приборов",
"date": "Дата",
Expand All @@ -13,8 +14,11 @@
"goodMorning": "Доброе утро",
"language": "Язык",
"logIn": "Войти",
"name": "Имя",
"password": "Пароль",
"recurringDescription": "Это повторяющаяся транзакция—создайте ее для меня в будущем",
"register": "Зарегистрируй",
"repeatPassword": "Повтори пароль",
"spending": "Расход",
"spendingDescriptionPlaceholder": "Подарок на день рождения для Анжелы",
"tag": "Тег",
Expand Down
5 changes: 5 additions & 0 deletions routes/api.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
<?php

use App\Http\Controllers\Api\ActivitiesController;
use App\Http\Controllers\Api\CurrencyController;
use App\Http\Controllers\Api\DashboardController;
use App\Http\Controllers\Api\LogInController;
use App\Http\Controllers\Api\RecurringController;
use App\Http\Controllers\Api\RegisterController;
use App\Http\Controllers\Api\SettingsController;
use App\Http\Controllers\Api\TagController;
use App\Http\Controllers\Api\TransactionController;
use Illuminate\Support\Facades\Route;

Route::get('/currencies', [CurrencyController::class, 'index']);

Route::post('/log-in', LogInController::class);
Route::post('/register', RegisterController::class);

Route::middleware('resolve-api-key')
->group(function () {
Expand Down
Loading