-
-
diff --git a/app/components/multimedia/contentDetail.vue b/app/components/multimedia/contentDetail.vue
new file mode 100644
index 000000000..5239cd3ff
--- /dev/null
+++ b/app/components/multimedia/contentDetail.vue
@@ -0,0 +1,182 @@
+
+
+
+
+
+ {{ contentData?.first_name }} {{ contentData?.last_name }}
+
+
+
+ md:notifications_outlined
+ follow
+
+
+
+
+
+
+
+
Book chapters
+
+ -
+ {{ item.title }}
+
+ -
+ {{ chapter.title }}
+
+
+
+
+
+
+
+ md:files_outlined
+ {{ contentData?.content_type_title }}
+
+
+ md:update
+ {{ fromNowLocal(contentData?.up_date) }}
+
+
+
+
+
+
+ {{ contentData?.section_title }}
+
+
+
+ {{ contentData?.base_title }}
+
+
+
+ {{ contentData?.lesson_title }}
+
+
+
+
+
+
+
diff --git a/app/components/multimedia/detail/DescriptionSection.vue b/app/components/multimedia/detail/DescriptionSection.vue
deleted file mode 100644
index 1a0f28ebd..000000000
--- a/app/components/multimedia/detail/DescriptionSection.vue
+++ /dev/null
@@ -1,170 +0,0 @@
-
-
-
-
-
-
- Description
-
-
- Book chapters
-
-
-
-
-
-
-
-
- mdi-pencil
-
-
-
-
-
- mdi-check
-
-
-
-
-
-
-
-
- -
- {{ item.title }}
-
- -
- {{ chapter.title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/multimedia/detail/DetailSidebar.vue b/app/components/multimedia/detail/DetailSidebar.vue
deleted file mode 100644
index 33892ae39..000000000
--- a/app/components/multimedia/detail/DetailSidebar.vue
+++ /dev/null
@@ -1,278 +0,0 @@
-
-
-
-
-
-
-
-
- {{ firstName }} {{ lastName }}
-
-
-
-
-
-
-
- md:folder
-
- File type: {{ contentTypeTitle }}
-
-
-
- md:auto_stories
-
- Page count: {{ filePages }}
-
-
-
- md:visibility
-
- Viewed: {{ views }}
-
-
-
- md:calendar_month
-
- Last update: {{ formatDate(upDate) }}
-
-
-
-
- md:bug_report
-
- Crash report
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Download {{ fileExt.toUpperCase() }}{{ showPrice ? " | " + price + " GEM" : "" }}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/multimedia/detail/DownloadSection.vue b/app/components/multimedia/detail/DownloadSection.vue
deleted file mode 100644
index 4fa2596c2..000000000
--- a/app/components/multimedia/detail/DownloadSection.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
- Login
-
- (register)
-
- to download and charge your wallet.
-
-
- Your wallet charge is ${{ credit }}
- (Top Up Wallet)
-
-
-
-
-
-
-
-
diff --git a/app/components/multimedia/detail/MobileOrderSection.vue b/app/components/multimedia/detail/MobileOrderSection.vue
deleted file mode 100644
index bf5d5c13f..000000000
--- a/app/components/multimedia/detail/MobileOrderSection.vue
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Download {{ fileExt.toUpperCase() }}{{ showPrice ? " | " + price+ " GEM" : "" }}
-
-
-
-
-
-
-
-
-
- Login
-
- (register)
-
- to download and charge.
-
-
- Your wallet charge is ${{ credit }}
- (Top Up Wallet)
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/multimedia/detail/ShareDialog.vue b/app/components/multimedia/detail/ShareDialog.vue
deleted file mode 100644
index d18d0ced8..000000000
--- a/app/components/multimedia/detail/ShareDialog.vue
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
-
- md:share
- Share
-
-
-
-
-
-
-
- Share this content:
-
-
-
-
-
- md:content_copy
-
-
- {{ copyBtnText }}
-
-
-
-
- WhatsApp
-
-
-
-
- Telegram
-
-
-
-
-
-
- close
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/multimedia/detail/TagSection.vue b/app/components/multimedia/detail/TagSection.vue
deleted file mode 100644
index 343162ca7..000000000
--- a/app/components/multimedia/detail/TagSection.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- {{ sectionTitle }}
-
-
-
-
-
- {{ baseTitle }}
-
-
-
-
-
- {{ lessonTitle }}
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/multimedia/downloadButton.vue b/app/components/multimedia/downloadButton.vue
new file mode 100644
index 000000000..e1a98121e
--- /dev/null
+++ b/app/components/multimedia/downloadButton.vue
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/multimedia/modal/edit.vue b/app/components/multimedia/modal/edit.vue
new file mode 100644
index 000000000..91b54771d
--- /dev/null
+++ b/app/components/multimedia/modal/edit.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+ Discard
+
+
+
+ Submit
+
+
+
+
+
+
+
+
diff --git a/app/components/multimedia/previewCard.vue b/app/components/multimedia/previewCard.vue
new file mode 100644
index 000000000..d2cb1ec98
--- /dev/null
+++ b/app/components/multimedia/previewCard.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
diff --git a/app/components/common/detail/ContentDetailsSection.vue b/app/components/paper/contentDetailsSection.vue
similarity index 100%
rename from app/components/common/detail/ContentDetailsSection.vue
rename to app/components/paper/contentDetailsSection.vue
diff --git a/app/components/common/detail/DownloadAndPurchaseButtons.vue b/app/components/paper/downloadAndPurchaseButtons.vue
similarity index 68%
rename from app/components/common/detail/DownloadAndPurchaseButtons.vue
rename to app/components/paper/downloadAndPurchaseButtons.vue
index 430e37035..37cd33486 100644
--- a/app/components/common/detail/DownloadAndPurchaseButtons.vue
+++ b/app/components/paper/downloadAndPurchaseButtons.vue
@@ -265,14 +265,11 @@ type TypeFile = 'word' | 'pdf' | 'answer' | 'extra'
const props = defineProps
()
-const { $toast } = useNuxtApp()
-const { trackFileDownload } = useGtmEvents()
const auth = useAuth()
const router = useRouter()
const { xs } = useDisplay()
const { balance, isLoading } = useCoinBalance()
-const { downloadFile } = useDownload()
const showCoinPaymentModal = ref(false)
const showCoinAnimation = ref(false)
const isProcessingPayment = ref(false)
@@ -284,159 +281,50 @@ const pendingDownload = ref<{
} | null>(null)
const openModalDownloadMobile = ref(false)
-const handleDownloadClick = async (type: TypeFile, price: number, extraId?: string) => {
- const downloadKey = extraId ? `${type}-${extraId}` : type
- priceFile.value = price
-
- // Set loading state and progress tracking
- downloadingItems.value.add(downloadKey)
- downloadProgress.value[downloadKey] = 0
- if (auth.isAuthenticated.value) {
- startDownload(type, extraId)
- }
- else {
- downloadingItems.value.delete(downloadKey)
- Reflect.deleteProperty(downloadProgress.value, downloadKey)
- router.push({})
- setTimeout(() => {
- router.push({ query: { auth_form: 'login', auth_noredirect: 'true' } })
- }, 100)
- }
-}
-
-// Track download progress for each button
-const downloadProgress = ref>({})
-const downloadingItems = ref>(new Set())
-
-const getDownloadProgress = (type: TypeFile, extraId?: string) => {
- const key = extraId ? `${type}-${extraId}` : type
- return downloadProgress.value[key] || 0
-}
-
-const isDownloading = (type: TypeFile, extraId?: string) => {
- const key = extraId ? `${type}-${extraId}` : type
- return downloadingItems.value.has(key)
-}
-
-const startDownload = async (type: TypeFile, extraId?: string) => {
- trackFileDownload({
+const {
+ clearDownload,
+ getDownloadProgress,
+ isDownloading,
+ startDownload,
+} = useDownloadWithProgress({
+ contentType: 'PastPaper',
+ id: props.id,
+ trackPayload: () => ({
file_type: 'past_paper',
file_name: props.title,
file_url: props.titleUrl,
- })
-
- const downloadKey = extraId ? `${type}-${extraId}` : type
- let progressInterval: ReturnType | null = null
-
- try {
- // Simulate progressive loading for API call
- progressInterval = setInterval(() => {
- const currentProgress = downloadProgress.value[downloadKey] ?? 0
- if (currentProgress < 50) {
- downloadProgress.value[downloadKey] = currentProgress + Math.random() * 15
- }
- }, 100)
-
- const response = await downloadFile({
- contentType: 'PastPaper',
- fileType: type,
- id: Number(props.id),
- extraId: extraId ? Number(extraId) : undefined,
- })
-
- // Update progress to 60% after API response
- downloadProgress.value[downloadKey] = 60
- clearInterval(progressInterval)
- progressInterval = null
-
- // Create a custom fetch with progress tracking
- if (response.succeeded && response.data) {
- if (response.data.url) {
- const xhr = new XMLHttpRequest()
- xhr.open('GET', response.data.url, true)
- xhr.responseType = 'blob'
-
- xhr.onprogress = (event) => {
- if (event.lengthComputable) {
- const percentComplete = 60 + (event.loaded / event.total) * 40
- downloadProgress.value[downloadKey] = Math.min(percentComplete, 100)
- }
- }
-
- xhr.onload = () => {
- if (xhr.status === 200) {
- downloadProgress.value[downloadKey] = 100
-
- const blob = xhr.response
- const url = window.URL.createObjectURL(blob)
-
- const a = document.createElement('a')
- a.href = url
- a.download = response.data?.name || 'file.pdf'
- document.body.appendChild(a)
- a.click()
-
- a.remove()
- window.URL.revokeObjectURL(url)
- downloadIssueLink.value = response.data?.url || ''
- if (response.data?.spent) {
- showCoinAnimation.value = true
- }
- else {
- downloadIssue.value = true
- }
-
- setTimeout(() => {
- downloadingItems.value.delete(downloadKey)
- Reflect.deleteProperty(downloadProgress.value, downloadKey)
- }, 1000)
- }
- }
-
- xhr.onerror = () => {
- downloadingItems.value.delete(downloadKey)
- Reflect.deleteProperty(downloadProgress.value, downloadKey)
- $toast.error('Download failed. Please try again.')
- }
-
- xhr.send()
- }
- if (response.data.upgradeSuggestions && response.data.upgradeSuggestions.length > 0) {
- showCoinPaymentModal.value = true
- }
+ }),
+ onDownloaded: (data) => {
+ downloadIssueLink.value = data.url || ''
+ if (data.spent) {
+ showCoinAnimation.value = true
}
else {
- if (response.errors && response.errors.length > 0) {
- const messgage = response.errors[0].message
- if (messgage == 'InsufficientBalance') {
- showCoinPaymentModal.value = true
- }
- }
- downloadingItems.value.delete(downloadKey)
- Reflect.deleteProperty(downloadProgress.value, downloadKey)
- }
- }
- catch (error: unknown) {
- console.error('Download failed:', error)
- downloadingItems.value.delete(downloadKey)
- Reflect.deleteProperty(downloadProgress.value, downloadKey)
- $toast.error('Download failed. Please try again.')
- }
- finally {
- if (progressInterval) {
- clearInterval(progressInterval)
+ downloadIssue.value = true
}
+ },
+ onInsufficientBalance: () => {
+ showCoinPaymentModal.value = true
+ },
+ onUpgradeSuggestions: () => {
+ showCoinPaymentModal.value = true
+ },
+})
+
+const handleDownloadClick = async (type: TypeFile, price: number, extraId?: string) => {
+ priceFile.value = price
+ pendingDownload.value = {
+ type,
+ extraId,
}
+
+ startDownload({ type, extraId })
}
const handleCoinPaymentClose = () => {
showCoinPaymentModal.value = false
if (pendingDownload.value) {
- const downloadKey = pendingDownload.value.extraId
- ? `${pendingDownload.value.type}-${pendingDownload.value.extraId}`
- : pendingDownload.value.type
- downloadingItems.value.delete(downloadKey)
- Reflect.deleteProperty(downloadProgress.value, downloadKey)
+ clearDownload(pendingDownload.value.type, pendingDownload.value.extraId)
}
pendingDownload.value = null
}
diff --git a/app/components/common/detail/PreviewActionCard.vue b/app/components/paper/previewActionCard.vue
similarity index 100%
rename from app/components/common/detail/PreviewActionCard.vue
rename to app/components/paper/previewActionCard.vue
diff --git a/app/components/profile/registerContent.vue b/app/components/profile/registerContent.vue
index fb59c7c34..4ad7783c4 100644
--- a/app/components/profile/registerContent.vue
+++ b/app/components/profile/registerContent.vue
@@ -22,7 +22,7 @@
v-for="item in 10"
:key="item"
>
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ md:chevron_backward
+
+
+ {{ contentData.title }}
+
+
+ md:chevron_forward
+
+
+
+
+ md:edit
+
+
+
+
+
+
+
-
-
-
-
- mdi-check
-
-
-
-
+
+
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+ md:warning_outlined
+ Crash report
+
-
-
-
-
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
-
-
diff --git a/app/pages/paper/[id]/[[slug]].vue b/app/pages/paper/[id]/[[slug]].vue
index 230e80eef..6c4afd397 100644
--- a/app/pages/paper/[id]/[[slug]].vue
+++ b/app/pages/paper/[id]/[[slug]].vue
@@ -29,7 +29,7 @@
md="4"
class="d-flex justify-center justify-md-start"
>
-