604 lines
23 KiB
JSON
604 lines
23 KiB
JSON
{
|
|
"version": "1.0.0",
|
|
"layout_name": "auth/reset_password",
|
|
"permissions": [],
|
|
"extends": "_user_base",
|
|
"meta": {
|
|
"title": "$t:auth.reset_password.title",
|
|
"guest_only": true
|
|
},
|
|
"data_sources": [
|
|
{
|
|
"id": "tokenValidation",
|
|
"label_key": "$t:editor.data_source.tokenValidation",
|
|
"type": "api",
|
|
"endpoint": "/api/auth/validate-reset-token",
|
|
"method": "POST",
|
|
"auto_fetch": true,
|
|
"auth_required": false,
|
|
"params": {
|
|
"token": "{{query.token ?? ''}}",
|
|
"email": "{{query.email ?? ''}}"
|
|
},
|
|
"loading_strategy": "blocking",
|
|
"initLocal": {
|
|
"tokenValid": "{{data.valid ?? false}}"
|
|
},
|
|
"errorHandling": {
|
|
"422": {
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"tokenError": true
|
|
}
|
|
},
|
|
"default": {
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"tokenError": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"slots": {
|
|
"content": [
|
|
{
|
|
"comment": "본인 계정 모달 - 로그인된 사용자 이메일과 토큰 이메일이 일치하는 경우",
|
|
"type": "composite",
|
|
"name": "Modal",
|
|
"props": {
|
|
"isOpen": "{{!!_global?.currentUser?.uuid && query.email === _global?.currentUser?.email}}",
|
|
"title": "$t:auth.logged_in_redirect.title",
|
|
"width": "400px",
|
|
"closeOnBackdropClick": false
|
|
},
|
|
"actions": [
|
|
{
|
|
"event": "onClose",
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": { "path": "/" }
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "text-gray-600 dark:text-gray-400"
|
|
},
|
|
"text": "$t:auth.logged_in_redirect.message"
|
|
},
|
|
{
|
|
"comment": "Footer 버튼 영역",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex justify-end gap-3 mt-6"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 cursor-pointer"
|
|
},
|
|
"text": "$t:auth.logged_in_redirect.go_home",
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": { "path": "/" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors cursor-pointer"
|
|
},
|
|
"text": "$t:auth.logged_in_redirect.change_password",
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": { "path": "/mypage/change-password" }
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "타인 계정 모달 - 로그인된 사용자 이메일과 토큰 이메일이 다른 경우",
|
|
"type": "composite",
|
|
"name": "Modal",
|
|
"props": {
|
|
"isOpen": "{{!!_global?.currentUser?.uuid && query.email !== _global?.currentUser?.email}}",
|
|
"title": "$t:auth.different_account.title",
|
|
"width": "400px",
|
|
"closeOnBackdropClick": false
|
|
},
|
|
"actions": [
|
|
{
|
|
"event": "onClose",
|
|
"type": "click",
|
|
"handler": "conditions",
|
|
"params": {
|
|
"conditions": [
|
|
{
|
|
"if": "{{!_local.isLoggingOut}}",
|
|
"then": {
|
|
"handler": "navigate",
|
|
"params": { "path": "/" }
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "text-gray-600 dark:text-gray-400"
|
|
},
|
|
"text": "$t:auth.different_account.message"
|
|
},
|
|
{
|
|
"comment": "Footer 버튼 영역",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex justify-end gap-3 mt-6"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
|
|
"disabled": "{{_local.isLoggingOut}}"
|
|
},
|
|
"text": "$t:auth.different_account.go_home",
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": { "path": "/" }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "button",
|
|
"className": "flex items-center justify-center gap-2 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed",
|
|
"disabled": "{{_local.isLoggingOut}}"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local.isLoggingOut}}",
|
|
"props": {
|
|
"className": "w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"text": "{{_local.isLoggingOut ? '$t:auth.different_account.logging_out' : '$t:auth.different_account.logout'}}"
|
|
}
|
|
],
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isLoggingOut": true
|
|
}
|
|
},
|
|
{
|
|
"handler": "logout",
|
|
"onSuccess": {
|
|
"handler": "refresh"
|
|
},
|
|
"onError": {
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isLoggingOut": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "toast",
|
|
"params": {
|
|
"type": "error",
|
|
"message": "$t:auth.different_account.logout_failed"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"blur_until_loaded": "{{_global?.currentUser?.uuid}}",
|
|
"props": {
|
|
"className": "min-h-[60vh] flex items-center justify-center py-12 px-4"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "비밀번호 재설정 폼",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "w-full max-w-md"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "bg-white dark:bg-gray-800 rounded-lg shadow-md p-8"
|
|
},
|
|
"responsive": {
|
|
"portable": {
|
|
"props": {
|
|
"className": "bg-white dark:bg-gray-800 rounded-lg shadow-md p-6"
|
|
}
|
|
}
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "헤더",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-center mb-8"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "H1",
|
|
"props": {
|
|
"className": "text-2xl font-bold text-gray-900 dark:text-white mb-2"
|
|
},
|
|
"text": "$t:auth.reset_password.title"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "text-gray-600 dark:text-gray-400"
|
|
},
|
|
"text": "$t:auth.reset_password.subtitle"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "토큰 에러 메시지",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local?.tokenError}}",
|
|
"props": {
|
|
"className": "text-center"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "w-16 h-16 mx-auto mb-4 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "xmark",
|
|
"size": "xl",
|
|
"color": "text-red-600 dark:text-red-400"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "text-red-700 dark:text-red-300 mb-6"
|
|
},
|
|
"text": "$t:auth.reset_password.token_invalid"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "flex flex-col sm:flex-row gap-3 justify-center"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors cursor-pointer whitespace-nowrap"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/login"
|
|
}
|
|
}
|
|
],
|
|
"text": "$t:auth.reset_password.go_to_login"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "px-6 py-3 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors cursor-pointer whitespace-nowrap"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/"
|
|
}
|
|
}
|
|
],
|
|
"text": "$t:auth.reset_password.go_to_home"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "성공 메시지",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "text-center"
|
|
},
|
|
"if": "{{_local?.success && !_local?.tokenError}}",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"props": {
|
|
"className": "w-16 h-16 mx-auto mb-4 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center"
|
|
},
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Icon",
|
|
"props": {
|
|
"name": "check",
|
|
"size": "xl",
|
|
"color": "text-green-600 dark:text-green-400"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "P",
|
|
"props": {
|
|
"className": "text-green-700 dark:text-green-300 mb-4"
|
|
},
|
|
"text": "$t:auth.reset_password.success"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"className": "inline-block px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors cursor-pointer"
|
|
},
|
|
"actions": [
|
|
{
|
|
"type": "click",
|
|
"handler": "navigate",
|
|
"params": {
|
|
"path": "/login"
|
|
}
|
|
}
|
|
],
|
|
"text": "$t:auth.login"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "폼",
|
|
"type": "basic",
|
|
"name": "Form",
|
|
"dataKey": "form",
|
|
"props": {
|
|
"id": "form",
|
|
"className": "space-y-6"
|
|
},
|
|
"if": "{{!_local?.success && !_local?.tokenError}}",
|
|
"actions": [
|
|
{
|
|
"type": "submit",
|
|
"handler": "sequence",
|
|
"actions": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSubmitting": true
|
|
}
|
|
},
|
|
{
|
|
"handler": "apiCall",
|
|
"target": "/api/auth/reset-password",
|
|
"params": {
|
|
"method": "POST",
|
|
"body": {
|
|
"token": "{{query.token ?? ''}}",
|
|
"email": "{{query.email ?? ''}}",
|
|
"password": "{{form?.password}}",
|
|
"password_confirmation": "{{form?.password_confirmation}}"
|
|
}
|
|
},
|
|
"onSuccess": {
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSubmitting": false,
|
|
"success": true
|
|
}
|
|
},
|
|
"onError": [
|
|
{
|
|
"handler": "setState",
|
|
"params": {
|
|
"target": "local",
|
|
"isSubmitting": false
|
|
}
|
|
},
|
|
{
|
|
"handler": "toast",
|
|
"params": {
|
|
"type": "error",
|
|
"message": "{{error.message}}"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"children": [
|
|
{
|
|
"comment": "새 비밀번호",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
|
},
|
|
"text": "$t:auth.reset_password.password"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "PasswordInput",
|
|
"props": {
|
|
"name": "password",
|
|
"placeholder": "$t:auth.reset_password.password_placeholder|count=8",
|
|
"className": "w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed",
|
|
"required": true,
|
|
"showToggle": true,
|
|
"showValidation": true,
|
|
"enableRules": [
|
|
"minLength:8"
|
|
],
|
|
"disabled": "{{_local?.isSubmitting ?? false}}"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "비밀번호 확인",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"children": [
|
|
{
|
|
"type": "basic",
|
|
"name": "Label",
|
|
"props": {
|
|
"className": "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"
|
|
},
|
|
"text": "$t:auth.reset_password.password_confirm"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "PasswordInput",
|
|
"props": {
|
|
"name": "password_confirmation",
|
|
"placeholder": "$t:auth.reset_password.password_confirm_placeholder",
|
|
"className": "w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-primary-500 focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed",
|
|
"required": true,
|
|
"showToggle": true,
|
|
"isConfirmField": true,
|
|
"confirmTarget": "{{_local?.form?.password ?? ''}}",
|
|
"disabled": "{{_local?.isSubmitting ?? false}}"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"comment": "제출 버튼",
|
|
"type": "basic",
|
|
"name": "Button",
|
|
"props": {
|
|
"type": "submit",
|
|
"className": "w-full py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2",
|
|
"disabled": "{{_local?.isSubmitting ?? false}}"
|
|
},
|
|
"children": [
|
|
{
|
|
"comment": "스피너",
|
|
"type": "basic",
|
|
"name": "Div",
|
|
"if": "{{_local?.isSubmitting}}",
|
|
"props": {
|
|
"className": "w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"
|
|
}
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{!_local?.isSubmitting}}",
|
|
"text": "$t:auth.reset_password.submit"
|
|
},
|
|
{
|
|
"type": "basic",
|
|
"name": "Span",
|
|
"if": "{{_local?.isSubmitting}}",
|
|
"text": "$t:auth.reset_password.processing"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
} |