feat(billing): cap each owner's stored file volume
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -46,6 +46,31 @@ const showOwnRecordsBanner = computed(
|
||||
);
|
||||
const todayLabel = computed(() => formatJalaliShort(new Date()));
|
||||
|
||||
function formatBytes(bytes: number): string {
|
||||
const n = Math.max(0, bytes);
|
||||
const units: Array<[number, string]> = [
|
||||
[1024 ** 3, 'گیگابایت'],
|
||||
[1024 ** 2, 'مگابایت'],
|
||||
[1024, 'کیلوبایت'],
|
||||
];
|
||||
for (const [size, label] of units) {
|
||||
if (n >= size) {
|
||||
const value = n / size;
|
||||
const text = value >= 10 ? value.toFixed(0) : value.toFixed(1);
|
||||
return `${toFaDigits(text)} ${label}`;
|
||||
}
|
||||
}
|
||||
return `${toFaDigits(Math.round(n))} بایت`;
|
||||
}
|
||||
|
||||
const storageBanner = computed(() => {
|
||||
const storage = auth.user?.storage;
|
||||
if (!storage || storage.level === 'ok' || storage.level === 'unlimited' || storage.quotaBytes == null) {
|
||||
return null;
|
||||
}
|
||||
return storage;
|
||||
});
|
||||
|
||||
const SIDEBAR_KEY = 'mento_sidebar_collapsed';
|
||||
|
||||
function readSidebarCollapsed() {
|
||||
@@ -914,6 +939,21 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p
|
||||
v-if="storageBanner"
|
||||
class="storage-banner"
|
||||
:class="storageBanner.level === 'full' ? 'full' : 'warn'"
|
||||
>
|
||||
<template v-if="storageBanner.level === 'full'">
|
||||
سقف حجم فایل پر شده است ({{ formatBytes(storageBanner.usedBytes) }} از
|
||||
{{ formatBytes(storageBanner.quotaBytes ?? 0) }}). تا شارژ حجم، آپلود جدید ممکن نیست.
|
||||
</template>
|
||||
<template v-else>
|
||||
حجم فایل به {{ toFaDigits(storageBanner.percent ?? 80) }}٪ رسیده
|
||||
({{ formatBytes(storageBanner.usedBytes) }} از {{ formatBytes(storageBanner.quotaBytes ?? 0) }}).
|
||||
</template>
|
||||
</p>
|
||||
|
||||
<main class="content">
|
||||
<RouterView />
|
||||
<GamificationToaster v-if="moduleAllowed('gamification')" />
|
||||
@@ -1409,6 +1449,23 @@ onUnmounted(() => {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.storage-banner {
|
||||
margin: 0 0 0.75rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-radius: 12px;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.storage-banner.warn {
|
||||
background: #fff7ed;
|
||||
color: #9a3412;
|
||||
}
|
||||
|
||||
.storage-banner.full {
|
||||
background: #fef2f2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.sidebar-foot {
|
||||
margin-top: auto;
|
||||
display: grid;
|
||||
|
||||
Reference in New Issue
Block a user