한도 도달 시 추가 버튼 비활성 + '무료 종류별 2개·유료 무제한' 안내, openCreate 가드. 백엔드 400 메시지는 폼 에러로 폴백 노출. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeUnmount, onMounted, reactive, ref, watch, nextTick } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch, nextTick } from 'vue'
|
||||||
import Sortable from 'sortablejs'
|
import Sortable from 'sortablejs'
|
||||||
import { accountApi } from '@/api/accountApi'
|
import { accountApi } from '@/api/accountApi'
|
||||||
import { useDialog } from '@/composables/dialog'
|
import { useDialog } from '@/composables/dialog'
|
||||||
|
import { useAuthStore } from '@/stores/auth'
|
||||||
import IconBtn from '@/components/ui/IconBtn.vue'
|
import IconBtn from '@/components/ui/IconBtn.vue'
|
||||||
import AppModal from '@/components/ui/AppModal.vue'
|
import AppModal from '@/components/ui/AppModal.vue'
|
||||||
|
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
|
const auth = useAuthStore()
|
||||||
|
|
||||||
const TABS = [
|
const TABS = [
|
||||||
{ key: 'BANK', label: '은행계좌' },
|
{ key: 'BANK', label: '은행계좌' },
|
||||||
@@ -32,6 +34,13 @@ const networth = ref({ totalAssets: 0, totalLiabilities: 0, netWorth: 0 })
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref(null)
|
const error = ref(null)
|
||||||
const activeType = ref('BANK')
|
const activeType = ref('BANK')
|
||||||
|
// 무료 회원 계좌 등록 한도: 종류별 2개(유료 무제한). 백엔드에서도 강제.
|
||||||
|
const FREE_WALLET_LIMIT = 2
|
||||||
|
const atWalletLimit = computed(
|
||||||
|
() =>
|
||||||
|
!auth.isPremium &&
|
||||||
|
wallets.value.filter((w) => w.type === activeType.value).length >= FREE_WALLET_LIMIT,
|
||||||
|
)
|
||||||
|
|
||||||
const formOpen = ref(false)
|
const formOpen = ref(false)
|
||||||
const editId = ref(null)
|
const editId = ref(null)
|
||||||
@@ -241,6 +250,13 @@ async function load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openCreate() {
|
function openCreate() {
|
||||||
|
if (atWalletLimit.value) {
|
||||||
|
dialog.alert(
|
||||||
|
`무료 회원은 종류별 계좌를 ${FREE_WALLET_LIMIT}개까지 등록할 수 있어요. 유료로 업그레이드하면 무제한이에요.`,
|
||||||
|
{ title: '등록 한도' },
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
editId.value = null
|
editId.value = null
|
||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
type: activeType.value,
|
type: activeType.value,
|
||||||
@@ -376,9 +392,10 @@ onBeforeUnmount(() => sortable?.destroy())
|
|||||||
@click="selectTab(t.key)"
|
@click="selectTab(t.key)"
|
||||||
>{{ t.label }}</button>
|
>{{ t.label }}</button>
|
||||||
</div>
|
</div>
|
||||||
<IconBtn class="tab-add" icon="plus" title="추가" variant="primary" @click="openCreate" />
|
<IconBtn class="tab-add" icon="plus" title="추가" variant="primary" :disabled="atWalletLimit" @click="openCreate" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p v-if="atWalletLimit" class="msg wallet-limit">무료 회원은 종류별 계좌를 {{ FREE_WALLET_LIMIT }}개까지 등록할 수 있어요 · 유료는 무제한</p>
|
||||||
<p v-if="error" class="msg error">{{ error }}</p>
|
<p v-if="error" class="msg error">{{ error }}</p>
|
||||||
<p v-if="loading" class="msg">불러오는 중...</p>
|
<p v-if="loading" class="msg">불러오는 중...</p>
|
||||||
|
|
||||||
@@ -905,6 +922,10 @@ button.primary {
|
|||||||
.msg.error {
|
.msg.error {
|
||||||
color: #c0392b;
|
color: #c0392b;
|
||||||
}
|
}
|
||||||
|
.msg.wallet-limit {
|
||||||
|
color: #b8860b;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
.wallet-form {
|
.wallet-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Reference in New Issue
Block a user