Compare commits

..

10 Commits

8 changed files with 87 additions and 17 deletions

View File

@ -24,6 +24,10 @@ public function register(): void
public function boot(): void public function boot(): void
{ {
$this->configureDefaults(); $this->configureDefaults();
if (app()->isProduction()) {
\Illuminate\Support\Facades\URL::forceScheme('https');
}
} }
/** /**

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
* Hapus constraint unique pada kolom email agar 1 email bisa dipakai banyak orang.
*/
public function up(): void
{
Schema::table('user_profiles', function (Blueprint $table) {
$table->dropUnique('user_profiles_email_unique');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('user_profiles', function (Blueprint $table) {
$table->unique('email');
});
}
};

View File

@ -16,19 +16,18 @@ nixPkgs = [
[phases.install] [phases.install]
cmds = [ cmds = [
"php -r \"copy('https://getcomposer.org/installer', 'composer-setup.php');\"", "curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && php /usr/local/bin/composer install --no-dev --optimize-autoloader --no-interaction",
"php composer-setup.php --install-dir=/usr/local/bin --filename=composer",
"php -r \"unlink('composer-setup.php');\"",
"composer install --no-dev --optimize-autoloader --no-interaction",
"npm ci" "npm ci"
] ]
[phases.build] [phases.build]
cmds = [ cmds = [
"php artisan wayfinder:generate",
"npm run build", "npm run build",
"php artisan config:cache", "php artisan config:cache",
"php artisan route:cache", "php artisan route:cache",
"php artisan view:cache" "php artisan view:cache",
"php artisan storage:link"
] ]
[start] [start]

View File

@ -254,7 +254,7 @@ .form-select {
font-weight: 300; font-weight: 300;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
transition: all var(--transition); transition: color var(--transition), border-color var(--transition), background var(--transition);
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
appearance: none; appearance: none;
@ -264,6 +264,12 @@ .form-select {
padding-right: 36px; padding-right: 36px;
} }
/* When a real value has been selected */
.form-select.is-selected {
color: var(--text-primary);
font-weight: 400;
}
.form-select:focus { .form-select:focus {
border-color: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.2);
background-color: rgba(255, 255, 255, 0.05); background-color: rgba(255, 255, 255, 0.05);

View File

@ -653,3 +653,10 @@ .image-section img:hover{
transform: scale(1.03) translateY(-4px); transform: scale(1.03) translateY(-4px);
filter: drop-shadow(0 16px 40px rgba(88,166,255,0.2)); filter: drop-shadow(0 16px 40px rgba(88,166,255,0.2));
} }
/* ===== VALIDATION ERROR STATE ===== */
.form-input.is-invalid,
.form-select.is-invalid {
border-color: rgba(248, 81, 73, 0.7) !important;
box-shadow: 0 0 0 3px rgba(248, 81, 73, 0.12);
}

View File

@ -174,7 +174,10 @@
</svg> </svg>
Nama Nama
</label> </label>
<input type="text" class="form-input" id="inputNama" name="name" placeholder="Nama lengkap" required> <input type="text" class="form-input @error('name') is-invalid @enderror" id="inputNama" name="name" placeholder="Nama lengkap" value="{{ old('name') }}" required>
@error('name')
<small style="color:#f87171;font-size:0.78rem;margin-top:4px;display:block;"> {{ $message }}</small>
@enderror
</div> </div>
<!-- Email --> <!-- Email -->
@ -186,7 +189,10 @@
</svg> </svg>
Email Email
</label> </label>
<input type="email" class="form-input" id="inputEmail" name="email" placeholder="Email" required> <input type="email" class="form-input @error('email') is-invalid @enderror" id="inputEmail" name="email" placeholder="Email" value="{{ old('email') }}" required>
@error('email')
<small style="color:#f87171;font-size:0.78rem;margin-top:4px;display:block;"> {{ $message }}</small>
@enderror
</div> </div>
<!-- Jenis Kelamin --> <!-- Jenis Kelamin -->
@ -258,8 +264,11 @@
</svg> </svg>
Register Voice Keyword Register Voice Keyword
</label> </label>
<input type="text" class="form-input" id="inputVoiceKeyword" name="voice_keyword" <input type="text" class="form-input @error('voice_keyword') is-invalid @enderror" id="inputVoiceKeyword" name="voice_keyword"
placeholder="Masukkan kata kunci suara (contoh: buka pintu)" required> placeholder="Masukkan kata kunci suara (contoh: buka pintu)" value="{{ old('voice_keyword') }}" required>
@error('voice_keyword')
<small style="color:#f87171;font-size:0.78rem;margin-top:4px;display:block;"> {{ $message }}</small>
@enderror
<small style="color: var(--text-muted, #8892a4); font-size: 0.75rem; margin-top: 4px; display:block;"> <small style="color: var(--text-muted, #8892a4); font-size: 0.75rem; margin-top: 4px; display:block;">
🎙️ Kata kunci ini akan digunakan untuk membuka pintu dengan suara 🎙️ Kata kunci ini akan digunakan untuk membuka pintu dengan suara
</small> </small>
@ -340,6 +349,19 @@ function toggleTheme() {
const mobileBtn = document.getElementById('mobileThemeBtn'); const mobileBtn = document.getElementById('mobileThemeBtn');
if (btn) btn.addEventListener('click', toggleTheme); if (btn) btn.addEventListener('click', toggleTheme);
if (mobileBtn) mobileBtn.addEventListener('click', toggleTheme); if (mobileBtn) mobileBtn.addEventListener('click', toggleTheme);
// Toggle warna select: abu-abu saat placeholder, putih saat sudah dipilih
document.querySelectorAll('.form-select').forEach(function(sel) {
function checkSelected() {
if (sel.value !== '') {
sel.classList.add('is-selected');
} else {
sel.classList.remove('is-selected');
}
}
sel.addEventListener('change', checkSelected);
checkSelected(); // cek kondisi awal (misal saat back/reload)
});
}); });
</script> </script>
</body> </body>

View File

@ -15,12 +15,14 @@
Route::get('/register', [RegisteredUserController::class, 'create']) Route::get('/register', [RegisteredUserController::class, 'create'])
->name('register'); ->name('register');
Route::post('/register', [RegisteredUserController::class, 'store']); Route::post('/register', [RegisteredUserController::class, 'store'])
->name('register.store');
Route::get('/login', [AuthenticatedSessionController::class, 'create']) Route::get('/login', [AuthenticatedSessionController::class, 'create'])
->name('login'); ->name('login');
Route::post('/login', [AuthenticatedSessionController::class, 'store']); Route::post('/login', [AuthenticatedSessionController::class, 'store'])
->name('login.store');
}); });
/* /*

View File

@ -6,7 +6,7 @@
Route::get('/', function () { Route::get('/', function () {
return redirect()->route('login'); return redirect()->route('login');
}); })->name('home');
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -26,10 +26,11 @@
Route::get('/histori', [UserProfileController::class,'histori'])->name('histori'); Route::get('/histori', [UserProfileController::class,'histori'])->name('histori');
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); // Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); // Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); // Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
}); });
require __DIR__.'/auth.php'; require __DIR__.'/auth.php';
require __DIR__.'/settings.php';