fix:매니저 드롭다운을 인라인 Alpine.js로 완전 재작성

- 별도 스크립트 함수 대신 x-data 인라인 정의
- @click.away를 @click.outside로 수정 (올바른 Alpine 문법)
- 스크립트 로드 순서 문제 해결

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
pro
2026-01-29 07:21:01 +09:00
parent 0f38aff96b
commit 92055a6187

View File

@@ -7,15 +7,54 @@
$assignedManager = $management?->manager;
$isSelf = !$assignedManager || $assignedManager->id === auth()->id();
$managerName = $assignedManager?->name ?? '본인';
// 매니저 목록 JSON (본인 제외는 컨트롤러에서 처리됨)
$managersJson = $allManagers->map(fn($m) => ['id' => $m->id, 'name' => $m->name, 'email' => $m->email])->values()->toJson();
$currentManagerJson = json_encode($assignedManager ? ['id' => $assignedManager->id, 'name' => $assignedManager->name, 'is_self' => $isSelf] : null);
@endphp
<div x-data="managerDropdown({{ $tenant->id }}, {{ json_encode($assignedManager ? ['id' => $assignedManager->id, 'name' => $assignedManager->name, 'is_self' => $isSelf] : null) }}, {{ $managersJson }})" class="relative">
<div x-data="{
tenantId: {{ $tenant->id }},
isOpen: false,
managers: {{ $managersJson }},
currentManager: {{ $currentManagerJson }},
toggle() {
this.isOpen = !this.isOpen;
},
close() {
this.isOpen = false;
},
selectManager(managerId, managerName) {
fetch('/sales/tenants/' + this.tenantId + '/assign-manager', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content,
},
body: JSON.stringify({ manager_id: managerId }),
})
.then(response => response.json())
.then(result => {
if (result.success) {
this.currentManager = {
id: result.manager.id,
name: result.manager.name,
is_self: managerId === 0 || result.manager.id === {{ auth()->id() }},
};
} else {
alert(result.message || '매니저 지정에 실패했습니다.');
}
})
.catch(error => {
console.error('매니저 지정 실패:', error);
alert('매니저 지정에 실패했습니다.');
});
this.close();
}
}" class="relative">
{{-- 드롭다운 트리거 --}}
<button
@click="toggle()"
@click.away="close()"
@click.outside="close()"
type="button"
class="inline-flex items-center gap-1 px-2.5 py-1 rounded text-xs font-medium transition-colors"
:class="isOpen ? 'bg-blue-100 text-blue-800 border border-blue-300' : 'bg-blue-50 text-blue-700 border border-blue-200 hover:bg-blue-100'">
@@ -95,69 +134,3 @@ class="w-full flex items-center gap-3 px-4 py-2 text-left text-sm hover:bg-gray-
</template>
</div>
</div>
@once
@push('scripts')
<script>
function managerDropdown(tenantId, initialManager, initialManagers) {
return {
tenantId: tenantId,
isOpen: false,
managers: initialManagers || [],
currentManager: initialManager,
toggle() {
this.isOpen = !this.isOpen;
},
close() {
this.isOpen = false;
},
async selectManager(managerId, managerName) {
console.log('selectManager called:', managerId, managerName, this.tenantId);
try {
const csrfToken = document.querySelector('meta[name="csrf-token"]');
if (!csrfToken) {
console.error('CSRF token not found');
alert('CSRF 토큰을 찾을 수 없습니다.');
return;
}
const response = await fetch(`/sales/tenants/${this.tenantId}/assign-manager`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken.content,
},
body: JSON.stringify({
manager_id: managerId,
}),
});
console.log('Response status:', response.status);
const result = await response.json();
console.log('Response:', result);
if (result.success) {
this.currentManager = {
id: result.manager.id,
name: result.manager.name,
is_self: managerId === 0 || result.manager.id === {{ auth()->id() }},
};
} else {
alert(result.message || '매니저 지정에 실패했습니다.');
}
} catch (error) {
console.error('매니저 지정 실패:', error);
alert('매니저 지정에 실패했습니다: ' + error.message);
}
this.close();
}
};
}
</script>
@endpush
@endonce