[FIX] 修復商品多語系儲存與讀取錯誤、新增自動語系名稱顯示、補強商品規格欄位及密碼顯示切換功能
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 47s
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 47s
This commit is contained in:
@@ -86,7 +86,14 @@ class ProductController extends Controller
|
|||||||
public function edit($id)
|
public function edit($id)
|
||||||
{
|
{
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$product = Product::with(['translations', 'company'])->findOrFail($id);
|
// 繞過 TenantScoped 載入翻譯,確保系統管理員能看到租戶公司的翻譯資料
|
||||||
|
$product = Product::with(['company'])->findOrFail($id);
|
||||||
|
$product->setRelation('translations',
|
||||||
|
Translation::withoutGlobalScopes()
|
||||||
|
->where('group', 'product')
|
||||||
|
->where('key', $product->name_dictionary_key)
|
||||||
|
->get()
|
||||||
|
);
|
||||||
$categories = ProductCategory::all();
|
$categories = ProductCategory::all();
|
||||||
$companies = $user->isSystemAdmin() ? Company::all() : collect();
|
$companies = $user->isSystemAdmin() ? Company::all() : collect();
|
||||||
|
|
||||||
@@ -131,10 +138,10 @@ class ProductController extends Controller
|
|||||||
? $request->company_id
|
? $request->company_id
|
||||||
: auth()->user()->company_id;
|
: auth()->user()->company_id;
|
||||||
|
|
||||||
// Store translations
|
// 儲存多語系翻譯(繞過 TenantScoped,避免系統管理員操作租戶資料時被過濾)
|
||||||
foreach ($request->names as $locale => $name) {
|
foreach ($request->names as $locale => $name) {
|
||||||
if (empty($name)) continue;
|
if (empty($name)) continue;
|
||||||
Translation::create([
|
Translation::withoutGlobalScopes()->create([
|
||||||
'group' => 'product',
|
'group' => 'product',
|
||||||
'key' => $dictKey,
|
'key' => $dictKey,
|
||||||
'locale' => $locale,
|
'locale' => $locale,
|
||||||
@@ -219,10 +226,10 @@ class ProductController extends Controller
|
|||||||
$dictKey = $product->name_dictionary_key ?: \Illuminate\Support\Str::uuid()->toString();
|
$dictKey = $product->name_dictionary_key ?: \Illuminate\Support\Str::uuid()->toString();
|
||||||
$company_id = $product->company_id;
|
$company_id = $product->company_id;
|
||||||
|
|
||||||
// Update or Create translations
|
// 更新或建立多語系翻譯(繞過 TenantScoped,避免系統管理員操作租戶資料時被過濾)
|
||||||
foreach ($request->names as $locale => $name) {
|
foreach ($request->names as $locale => $name) {
|
||||||
if (empty($name)) {
|
if (empty($name)) {
|
||||||
Translation::where([
|
Translation::withoutGlobalScopes()->where([
|
||||||
'group' => 'product',
|
'group' => 'product',
|
||||||
'key' => $dictKey,
|
'key' => $dictKey,
|
||||||
'locale' => $locale
|
'locale' => $locale
|
||||||
@@ -230,7 +237,7 @@ class ProductController extends Controller
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Translation::updateOrCreate(
|
Translation::withoutGlobalScopes()->updateOrCreate(
|
||||||
[
|
[
|
||||||
'group' => 'product',
|
'group' => 'product',
|
||||||
'key' => $dictKey,
|
'key' => $dictKey,
|
||||||
@@ -246,6 +253,7 @@ class ProductController extends Controller
|
|||||||
$data = [
|
$data = [
|
||||||
'category_id' => $request->category_id,
|
'category_id' => $request->category_id,
|
||||||
'name' => $request->names['zh_TW'] ?? ($product->name ?? 'Untitled'),
|
'name' => $request->names['zh_TW'] ?? ($product->name ?? 'Untitled'),
|
||||||
|
'name_dictionary_key' => $dictKey,
|
||||||
'barcode' => $request->barcode,
|
'barcode' => $request->barcode,
|
||||||
'spec' => $request->spec,
|
'spec' => $request->spec,
|
||||||
'manufacturer' => $request->manufacturer,
|
'manufacturer' => $request->manufacturer,
|
||||||
@@ -316,9 +324,9 @@ class ProductController extends Controller
|
|||||||
try {
|
try {
|
||||||
$product = Product::findOrFail($id);
|
$product = Product::findOrFail($id);
|
||||||
|
|
||||||
// Delete translations associated with this product
|
// 刪除與此商品關聯的翻譯資料(繞過 TenantScoped)
|
||||||
if ($product->name_dictionary_key) {
|
if ($product->name_dictionary_key) {
|
||||||
Translation::where('key', $product->name_dictionary_key)->delete();
|
Translation::withoutGlobalScopes()->where('key', $product->name_dictionary_key)->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete image
|
// Delete image
|
||||||
|
|||||||
@@ -48,6 +48,33 @@ class Product extends Model
|
|||||||
return $this->belongsTo(ProductCategory::class, 'category_id');
|
return $this->belongsTo(ProductCategory::class, 'category_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自動附加到 JSON/陣列輸出的屬性(供 Alpine.js 等前端使用)
|
||||||
|
*/
|
||||||
|
protected $appends = ['localized_name'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取得當前語系的商品名稱。
|
||||||
|
* 回退順序:當前語系 → zh_TW → name 欄位
|
||||||
|
*/
|
||||||
|
public function getLocalizedNameAttribute(): string
|
||||||
|
{
|
||||||
|
if ($this->relationLoaded('translations') && $this->translations->isNotEmpty()) {
|
||||||
|
$locale = app()->getLocale();
|
||||||
|
// 先找當前語系
|
||||||
|
$translation = $this->translations->firstWhere('locale', $locale);
|
||||||
|
if ($translation) {
|
||||||
|
return $translation->value;
|
||||||
|
}
|
||||||
|
// 回退至 zh_TW
|
||||||
|
$fallback = $this->translations->firstWhere('locale', 'zh_TW');
|
||||||
|
if ($fallback) {
|
||||||
|
return $fallback->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->name ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the translations for the product name.
|
* Get the translations for the product name.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -484,8 +484,20 @@
|
|||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{
|
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{
|
||||||
__('Password') }}</label>
|
__('Password') }}</label>
|
||||||
<input type="password" name="admin_password" class="luxury-input w-full"
|
<div x-data="{ show: false }" class="relative items-center">
|
||||||
placeholder="{{ __('Min 8 characters') }}">
|
<input :type="show ? 'text' : 'password'" name="admin_password" class="luxury-input w-full pr-12"
|
||||||
|
placeholder="{{ __('Min 8 characters') }}">
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-cyan-500 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
|||||||
@@ -366,9 +366,21 @@ $roleSelectConfig = [
|
|||||||
<span class="text-rose-500">*</span>
|
<span class="text-rose-500">*</span>
|
||||||
</template>
|
</template>
|
||||||
</label>
|
</label>
|
||||||
<input type="password" name="password" :required="!editing"
|
<div x-data="{ show: false }" class="relative items-center">
|
||||||
class="luxury-input @error('password') border-rose-500 @enderror"
|
<input :type="show ? 'text' : 'password'" name="password" :required="!editing"
|
||||||
placeholder="••••••••">
|
class="luxury-input w-full pr-12 @error('password') border-rose-500 @enderror"
|
||||||
|
placeholder="••••••••">
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-cyan-500 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end gap-x-4 pt-8">
|
<div class="flex justify-end gap-x-4 pt-8">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@php
|
@php
|
||||||
$names = [];
|
$names = [];
|
||||||
foreach(['zh_TW', 'en', 'ja'] as $locale) {
|
foreach(['zh_TW', 'en', 'ja'] as $locale) {
|
||||||
$names[$locale] = $product->translations->where('locale', $locale)->first()?->text ?? '';
|
$names[$locale] = $product->translations->where('locale', $locale)->first()?->value ?? '';
|
||||||
}
|
}
|
||||||
// If zh_TW translation is empty, fallback to product->name
|
// If zh_TW translation is empty, fallback to product->name
|
||||||
if (empty($names['zh_TW'])) {
|
if (empty($names['zh_TW'])) {
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ $roleSelectConfig = [
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-base font-extrabold text-slate-800 dark:text-slate-100 group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors">{{ $product->name }}</span>
|
<span class="text-base font-extrabold text-slate-800 dark:text-slate-100 group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors">{{ $product->localized_name }}</span>
|
||||||
<div class="flex items-center gap-2 mt-0.5">
|
<div class="flex items-center gap-2 mt-0.5">
|
||||||
@php
|
@php
|
||||||
$catName = $product->category->name ?? __('Uncategorized');
|
$catName = $product->category->name ?? __('Uncategorized');
|
||||||
@@ -236,7 +236,7 @@ $roleSelectConfig = [
|
|||||||
<div class="px-6 py-3 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between sticky top-0 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md z-20">
|
<div class="px-6 py-3 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between sticky top-0 bg-white/80 dark:bg-slate-900/80 backdrop-blur-md z-20">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-black text-slate-800 dark:text-white">{{ __('Product Details') }}</h2>
|
<h2 class="text-xl font-black text-slate-800 dark:text-white">{{ __('Product Details') }}</h2>
|
||||||
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-[0.2em] mt-1" x-text="selectedProduct?.name + ' (' + getCategoryName(selectedProduct?.category_id) + ')'"></p>
|
<p class="text-[11px] font-bold text-slate-400 uppercase tracking-[0.2em] mt-1" x-text="(selectedProduct?.localized_name || selectedProduct?.name) + ' (' + getCategoryName(selectedProduct?.category_id) + ')'"></p>
|
||||||
</div>
|
</div>
|
||||||
<button @click="isDetailOpen = false"
|
<button @click="isDetailOpen = false"
|
||||||
class="p-2 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors">
|
class="p-2 rounded-xl hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors">
|
||||||
@@ -281,6 +281,10 @@ $roleSelectConfig = [
|
|||||||
<span class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{ __('Barcode') }}</span>
|
<span class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{ __('Barcode') }}</span>
|
||||||
<div class="text-[15px] font-mono font-bold text-slate-700 dark:text-slate-200" x-text="selectedProduct?.barcode || '-'"></div>
|
<div class="text-[15px] font-mono font-bold text-slate-700 dark:text-slate-200" x-text="selectedProduct?.barcode || '-'"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="bg-slate-50 dark:bg-slate-800/40 p-5 rounded-2xl border border-slate-100 dark:border-slate-800/80 group hover:border-cyan-500/30 transition-colors">
|
||||||
|
<span class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{ __('Specification') }}</span>
|
||||||
|
<div class="text-[15px] font-bold text-slate-700 dark:text-slate-200" x-text="selectedProduct?.spec || '-'"></div>
|
||||||
|
</div>
|
||||||
<template x-if="selectedProduct?.metadata?.material_code">
|
<template x-if="selectedProduct?.metadata?.material_code">
|
||||||
<div class="bg-slate-50 dark:bg-slate-800/40 p-5 rounded-2xl border border-slate-100 dark:border-slate-800/80 group hover:border-cyan-500/30 transition-colors">
|
<div class="bg-slate-50 dark:bg-slate-800/40 p-5 rounded-2xl border border-slate-100 dark:border-slate-800/80 group hover:border-cyan-500/30 transition-colors">
|
||||||
<span class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{ __('Material Code') }}</span>
|
<span class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{ __('Material Code') }}</span>
|
||||||
@@ -387,7 +391,7 @@ $roleSelectConfig = [
|
|||||||
<img :src="selectedProduct?.image_url" class="max-w-full max-h-full rounded-[2.5rem] shadow-2xl border border-white/10 animate-luxury-in">
|
<img :src="selectedProduct?.image_url" class="max-w-full max-h-full rounded-[2.5rem] shadow-2xl border border-white/10 animate-luxury-in">
|
||||||
|
|
||||||
<div class="absolute bottom-[-4rem] left-1/2 -translate-x-1/2 text-white/60 text-sm font-bold tracking-widest uppercase animate-luxury-in" style="animation-delay: 200ms">
|
<div class="absolute bottom-[-4rem] left-1/2 -translate-x-1/2 text-white/60 text-sm font-bold tracking-widest uppercase animate-luxury-in" style="animation-delay: 200ms">
|
||||||
<span x-text="selectedProduct?.name"></span>
|
<span x-text="selectedProduct?.localized_name || selectedProduct?.name"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -83,17 +83,24 @@
|
|||||||
<!-- End Form Group -->
|
<!-- End Form Group -->
|
||||||
|
|
||||||
<!-- Form Group -->
|
<!-- Form Group -->
|
||||||
<div>
|
<div x-data="{ showPassword: false }">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center justify-between">
|
||||||
<label for="password" class="block text-sm mb-2 dark:text-white">密碼</label>
|
<label for="password" class="block text-sm mb-2 dark:text-white font-bold">密碼</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<input type="password" id="password" name="password" class="py-3 px-4 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-slate-900 dark:border-slate-700 dark:text-gray-400 dark:focus:ring-gray-600" required autocomplete="current-password">
|
<input :type="showPassword ? 'text' : 'password'" id="password" name="password"
|
||||||
<div class="hidden absolute inset-y-0 end-0 flex items-center pointer-events-none pe-3">
|
class="py-3 px-4 block w-full border-gray-200 dark:border-slate-700 bg-white dark:bg-slate-900 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 dark:text-gray-400 dark:focus:ring-gray-600 transition-all pr-12"
|
||||||
<svg class="h-5 w-5 text-red-500" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
|
required autocomplete="current-password">
|
||||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z"/>
|
<button type="button" @click="showPassword = !showPassword"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-gray-400 hover:text-blue-600 transition-colors">
|
||||||
|
<svg x-show="!showPassword" class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
<svg x-show="showPassword" x-cloak class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@if ($errors->get('password'))
|
@if ($errors->get('password'))
|
||||||
<p class="text-xs text-red-600 mt-2" id="password-error">{{ $errors->first('password') }}</p>
|
<p class="text-xs text-red-600 mt-2" id="password-error">{{ $errors->first('password') }}</p>
|
||||||
|
|||||||
@@ -12,21 +12,42 @@
|
|||||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Password -->
|
<div class="mt-4" x-data="{ show: false }">
|
||||||
<div class="mt-4">
|
|
||||||
<x-input-label for="password" :value="__('Password')" />
|
<x-input-label for="password" :value="__('Password')" />
|
||||||
<x-text-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
|
<div class="relative items-center mt-1">
|
||||||
|
<x-text-input id="password" class="block w-full pr-12" :type="show ? 'text' : 'password'" name="password" required autocomplete="new-password" />
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-blue-600 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Confirm Password -->
|
<!-- Confirm Password -->
|
||||||
<div class="mt-4">
|
<div class="mt-4" x-data="{ show: false }">
|
||||||
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
||||||
|
<div class="relative items-center mt-1">
|
||||||
<x-text-input id="password_confirmation" class="block mt-1 w-full"
|
<x-text-input id="password_confirmation" class="block w-full pr-12"
|
||||||
type="password"
|
:type="show ? 'text' : 'password'"
|
||||||
name="password_confirmation" required autocomplete="new-password" />
|
name="password_confirmation" required autocomplete="new-password" />
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-blue-600 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -13,22 +13,58 @@
|
|||||||
@csrf
|
@csrf
|
||||||
@method('put')
|
@method('put')
|
||||||
|
|
||||||
<div>
|
<div x-data="{ show: false }">
|
||||||
<x-input-label for="update_password_current_password" :value="__('Current Password')" class="text-xs font-black text-slate-500 uppercase tracking-widest mb-2 ml-1" />
|
<x-input-label for="update_password_current_password" :value="__('Current Password')" class="text-xs font-black text-slate-500 uppercase tracking-widest mb-2 ml-1" />
|
||||||
<input id="update_password_current_password" name="current_password" type="password" class="py-3 px-4 block w-full border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none" autocomplete="current-password" />
|
<div class="relative items-center">
|
||||||
|
<input id="update_password_current_password" name="current_password" :type="show ? 'text' : 'password'" class="py-3 px-4 block w-full border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none pr-12" autocomplete="current-password" />
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-cyan-500 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<x-input-error :messages="$errors->updatePassword->get('current_password')" class="mt-2" />
|
<x-input-error :messages="$errors->updatePassword->get('current_password')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div x-data="{ show: false }">
|
||||||
<x-input-label for="update_password_password" :value="__('New Password')" class="text-xs font-black text-slate-500 uppercase tracking-widest mb-2 ml-1" />
|
<x-input-label for="update_password_password" :value="__('New Password')" class="text-xs font-black text-slate-500 uppercase tracking-widest mb-2 ml-1" />
|
||||||
<input id="update_password_password" name="password" type="password" class="py-3 px-4 block w-full border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none" autocomplete="new-password" />
|
<div class="relative items-center">
|
||||||
|
<input id="update_password_password" name="password" :type="show ? 'text' : 'password'" class="py-3 px-4 block w-full border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none pr-12" autocomplete="new-password" />
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-cyan-500 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<x-input-error :messages="$errors->updatePassword->get('password')" class="mt-2" />
|
<x-input-error :messages="$errors->updatePassword->get('password')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div x-data="{ show: false }">
|
||||||
<x-input-label for="update_password_password_confirmation" :value="__('Confirm Password')" class="text-xs font-black text-slate-500 uppercase tracking-widest mb-2 ml-1" />
|
<x-input-label for="update_password_password_confirmation" :value="__('Confirm Password')" class="text-xs font-black text-slate-500 uppercase tracking-widest mb-2 ml-1" />
|
||||||
<input id="update_password_password_confirmation" name="password_confirmation" type="password" class="py-3 px-4 block w-full border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none" autocomplete="new-password" />
|
<div class="relative items-center">
|
||||||
|
<input id="update_password_password_confirmation" name="password_confirmation" :type="show ? 'text' : 'password'" class="py-3 px-4 block w-full border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900 rounded-2xl text-sm font-bold text-slate-700 dark:text-slate-200 focus:ring-4 focus:ring-cyan-500/10 focus:border-cyan-500 transition-all outline-none pr-12" autocomplete="new-password" />
|
||||||
|
<button type="button" @click="show = !show"
|
||||||
|
class="absolute inset-y-0 end-0 flex items-center z-20 px-4 cursor-pointer text-slate-400 hover:text-cyan-500 transition-colors">
|
||||||
|
<svg x-show="!show" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
<svg x-show="show" x-cloak class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<x-input-error :messages="$errors->updatePassword->get('password_confirmation')" class="mt-2" />
|
<x-input-error :messages="$errors->updatePassword->get('password_confirmation')" class="mt-2" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user