feat: catalog read cache (api + user apps) and clearer Zarrin accounting errors
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -241,7 +241,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { computed, nextTick, onActivated, onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Loading, PullRefresh } from 'vant'
|
||||
import Icon from '../../components/icon/Icon.vue'
|
||||
@@ -250,12 +250,15 @@ import IslandSheet from '../../components/ui/IslandSheet.vue'
|
||||
import { price } from '../../utils/filters'
|
||||
import { useSessionStore } from '../../stores/session'
|
||||
import { api, type CustomerDetail, type GoldPriceQuote } from '../../api/client'
|
||||
import { useCachedReads } from '../../api/cachedReads'
|
||||
import { KEYS } from '../../stores/queryCache'
|
||||
|
||||
const router = useRouter()
|
||||
const session = useSessionStore()
|
||||
const reads = useCachedReads()
|
||||
|
||||
const customer = ref<CustomerDetail | null>(null)
|
||||
const goldPrice = ref<GoldPriceQuote | null>(null)
|
||||
const customer = ref<CustomerDetail | null>(reads.peek<CustomerDetail>(KEYS.profile) ?? null)
|
||||
const goldPrice = ref<GoldPriceQuote | null>(reads.peek<GoldPriceQuote>(KEYS.goldPrice) ?? null)
|
||||
const refreshing = ref(false)
|
||||
|
||||
// The ledger stores the gram position as a signed figure — positive means the
|
||||
@@ -300,30 +303,34 @@ async function logOut() {
|
||||
router.push({ name: 'home' })
|
||||
}
|
||||
|
||||
async function loadDashboard() {
|
||||
if (session.isLoggedIn) {
|
||||
// Not wrapped before: a failure here (expired token, network blip) left
|
||||
// the exception uncaught, so onRefresh's refreshing.value = false never
|
||||
// ran and PullRefresh stayed stuck in its loading state — a working pull
|
||||
// gesture never dismissed it again until a full page reload.
|
||||
try {
|
||||
customer.value = await api.getMe()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
try {
|
||||
goldPrice.value = await api.getLatestGoldPrice()
|
||||
} catch {
|
||||
goldPrice.value = null
|
||||
}
|
||||
async function loadDashboard(force = false) {
|
||||
// Not wrapped before: a failure here (expired token, network blip) left
|
||||
// the exception uncaught, so onRefresh's refreshing.value = false never
|
||||
// ran and PullRefresh stayed stuck in its loading state — a working pull
|
||||
// gesture never dismissed it again until a full page reload.
|
||||
const [me, price] = await Promise.allSettled([
|
||||
// The balance on this tab is the one figure read fresh on every visit;
|
||||
// the cached copy only fills the screen until it arrives.
|
||||
session.isLoggedIn ? reads.me({ force: true }) : Promise.resolve(null),
|
||||
reads.goldPrice({ force }),
|
||||
])
|
||||
if (me.status === 'fulfilled') customer.value = me.value
|
||||
else console.log(me.reason)
|
||||
goldPrice.value = price.status === 'fulfilled' ? price.value : null
|
||||
}
|
||||
|
||||
async function onRefresh() {
|
||||
await loadDashboard()
|
||||
await loadDashboard(true)
|
||||
refreshing.value = false
|
||||
}
|
||||
|
||||
let activatedOnce = false
|
||||
onActivated(() => {
|
||||
// Kept alive by MasterLayout, so every later visit lands here, not in onMounted.
|
||||
if (activatedOnce) void loadDashboard()
|
||||
activatedOnce = true
|
||||
})
|
||||
|
||||
// First-paint entrance, mirroring HomeView's choreography exactly (module-scope
|
||||
// flag so it only replays on a full app reload, not on every tab switch).
|
||||
let hasRevealed = false
|
||||
|
||||
Reference in New Issue
Block a user