Compare commits
1 commit
996168d00c
...
e871bc1f19
| Author | SHA1 | Date | |
|---|---|---|---|
| e871bc1f19 |
1 changed files with 24 additions and 91 deletions
|
|
@ -1,52 +1,21 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useTimeAgo } from '@vueuse/core'
|
import { useTimeAgo } from '@vueuse/core'
|
||||||
import { DollarSign, TrendingUp, Lock, FileText, Trash2, Image as ImageIcon } from 'lucide-vue-next'
|
import { DollarSign, TrendingUp, FileText, Trash2, Image as ImageIcon } from 'lucide-vue-next'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Separator } from '@/components/ui/separator'
|
import { Separator } from '@/components/ui/separator'
|
||||||
import AddExpense from '@/modules/expenses/components/AddExpense.vue'
|
import AddExpense from '@/modules/expenses/components/AddExpense.vue'
|
||||||
import AddIncome from './AddIncome.vue'
|
import AddIncome from './AddIncome.vue'
|
||||||
import { useExpenseDrafts, type ExpenseDraft } from '../composables/useExpenseDrafts'
|
import { useExpenseDrafts, type ExpenseDraft } from '../composables/useExpenseDrafts'
|
||||||
import { useAuth } from '@/composables/useAuthService'
|
|
||||||
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
|
||||||
import type { ExpensesAPI } from '@/modules/expenses/services/ExpensesAPI'
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { drafts, hasDrafts, deleteDraft } = useExpenseDrafts()
|
const { drafts, hasDrafts, deleteDraft } = useExpenseDrafts()
|
||||||
const { user } = useAuth()
|
|
||||||
const expensesAPI = injectService<ExpensesAPI>(SERVICE_TOKENS.EXPENSES_API)
|
|
||||||
|
|
||||||
const showAddExpense = ref(false)
|
const showAddExpense = ref(false)
|
||||||
const showAddIncome = ref(false)
|
const showAddIncome = ref(false)
|
||||||
|
|
||||||
const permissionsLoaded = ref(false)
|
|
||||||
const canSubmitExpense = ref(true)
|
|
||||||
const canSubmitIncome = ref(true)
|
|
||||||
|
|
||||||
const expenseDisabled = computed(() => permissionsLoaded.value && !canSubmitExpense.value)
|
|
||||||
const incomeDisabled = computed(() => permissionsLoaded.value && !canSubmitIncome.value)
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const walletKey = user.value?.wallets?.[0]?.inkey
|
|
||||||
if (!walletKey) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const accounts = await expensesAPI.getAccounts(walletKey, true, true)
|
|
||||||
canSubmitExpense.value = accounts.some(
|
|
||||||
(a) => a.name === 'Expenses' || a.name.startsWith('Expenses:')
|
|
||||||
)
|
|
||||||
canSubmitIncome.value = accounts.some(
|
|
||||||
(a) => a.name === 'Income' || a.name.startsWith('Income:')
|
|
||||||
)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[RecordPage] Failed to load user permissions:', error)
|
|
||||||
} finally {
|
|
||||||
permissionsLoaded.value = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function handleExpenseSubmitted() {
|
function handleExpenseSubmitted() {
|
||||||
// Could refresh balance or show notification
|
// Could refresh balance or show notification
|
||||||
}
|
}
|
||||||
|
|
@ -81,68 +50,32 @@ function draftTimeAgo(isoDate: string) {
|
||||||
<!-- Action Cards -->
|
<!-- Action Cards -->
|
||||||
<div class="grid gap-4">
|
<div class="grid gap-4">
|
||||||
<!-- Add Expense Card -->
|
<!-- Add Expense Card -->
|
||||||
<div>
|
|
||||||
<button
|
<button
|
||||||
class="w-full flex items-start gap-4 p-5 rounded-xl border bg-card text-left transition-colors"
|
class="flex items-start gap-4 p-5 rounded-xl border bg-card text-left transition-colors hover:bg-accent/50 active:bg-accent/70"
|
||||||
:class="expenseDisabled
|
@click="showAddExpense = true"
|
||||||
? 'opacity-60 cursor-not-allowed'
|
|
||||||
: 'hover:bg-accent/50 active:bg-accent/70'"
|
|
||||||
:disabled="expenseDisabled"
|
|
||||||
@click="!expenseDisabled && (showAddExpense = true)"
|
|
||||||
>
|
>
|
||||||
<div
|
<div class="flex items-center justify-center w-12 h-12 rounded-full bg-red-100 dark:bg-red-900/20 shrink-0">
|
||||||
class="flex items-center justify-center w-12 h-12 rounded-full shrink-0"
|
<DollarSign class="w-6 h-6 text-red-600 dark:text-red-400" />
|
||||||
:class="expenseDisabled ? 'bg-muted' : 'bg-red-100 dark:bg-red-900/20'"
|
|
||||||
>
|
|
||||||
<DollarSign
|
|
||||||
class="w-6 h-6"
|
|
||||||
:class="expenseDisabled ? 'text-muted-foreground' : 'text-red-600 dark:text-red-400'"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<h2 class="text-lg font-semibold text-foreground">{{ t('libra.record.addExpense') }}</h2>
|
<h2 class="text-lg font-semibold text-foreground">{{ t('libra.record.addExpense') }}</h2>
|
||||||
<p class="text-sm text-muted-foreground mt-0.5">{{ t('libra.record.addExpenseDescription') }}</p>
|
<p class="text-sm text-muted-foreground mt-0.5">{{ t('libra.record.addExpenseDescription') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div v-if="expenseDisabled" class="mt-2 flex items-start gap-1.5 px-1">
|
|
||||||
<Lock class="w-3 h-3 mt-0.5 shrink-0 text-muted-foreground" />
|
|
||||||
<p class="text-[11px] leading-snug text-muted-foreground">
|
|
||||||
You don't have permission to submit expenses. Contact your administrator to request access.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Add Income Card -->
|
<!-- Add Income Card -->
|
||||||
<div>
|
|
||||||
<button
|
<button
|
||||||
class="w-full flex items-start gap-4 p-5 rounded-xl border bg-card text-left transition-colors"
|
class="flex items-start gap-4 p-5 rounded-xl border bg-card text-left transition-colors hover:bg-accent/50 active:bg-accent/70"
|
||||||
:class="incomeDisabled
|
@click="showAddIncome = true"
|
||||||
? 'opacity-60 cursor-not-allowed'
|
|
||||||
: 'hover:bg-accent/50 active:bg-accent/70'"
|
|
||||||
:disabled="incomeDisabled"
|
|
||||||
@click="!incomeDisabled && (showAddIncome = true)"
|
|
||||||
>
|
>
|
||||||
<div
|
<div class="flex items-center justify-center w-12 h-12 rounded-full bg-green-100 dark:bg-green-900/20 shrink-0">
|
||||||
class="flex items-center justify-center w-12 h-12 rounded-full shrink-0"
|
<TrendingUp class="w-6 h-6 text-green-600 dark:text-green-400" />
|
||||||
:class="incomeDisabled ? 'bg-muted' : 'bg-green-100 dark:bg-green-900/20'"
|
|
||||||
>
|
|
||||||
<TrendingUp
|
|
||||||
class="w-6 h-6"
|
|
||||||
:class="incomeDisabled ? 'text-muted-foreground' : 'text-green-600 dark:text-green-400'"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<h2 class="text-lg font-semibold text-foreground">{{ t('libra.record.addIncome') }}</h2>
|
<h2 class="text-lg font-semibold text-foreground">{{ t('libra.record.addIncome') }}</h2>
|
||||||
<p class="text-sm text-muted-foreground mt-0.5">{{ t('libra.record.addIncomeDescription') }}</p>
|
<p class="text-sm text-muted-foreground mt-0.5">{{ t('libra.record.addIncomeDescription') }}</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div v-if="incomeDisabled" class="mt-2 flex items-start gap-1.5 px-1">
|
|
||||||
<Lock class="w-3 h-3 mt-0.5 shrink-0 text-muted-foreground" />
|
|
||||||
<p class="text-[11px] leading-snug text-muted-foreground">
|
|
||||||
You don't have permission to record income. Contact your administrator to request access.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Drafts Section -->
|
<!-- Drafts Section -->
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue