@@ -27,7 +27,6 @@
-
@@ -62,4 +61,28 @@ function goToUrl() {
text-decoration: none;
color: black;
}
+
+.article-card-item {
+ min-width: 619px;
+ width: 100%;
+ border: 1px solid #e54757;
+ border-radius: 24px;
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+
+ @media (max-width: 1440px) {
+ min-width: 590px;
+ }
+
+ @media (min-width: 1024px) {
+ min-width: 470px;
+ }
+
+ @media (max-width: 768px) {
+ min-width: 361px;
+ }
+
+ @media (max-width: 425px) {
+ min-width: 280px;
+ }
+}
diff --git a/src/components/shared/TheEntries.vue b/src/components/shared/TheEntries.vue
index 6987b34c..96d236a1 100644
--- a/src/components/shared/TheEntries.vue
+++ b/src/components/shared/TheEntries.vue
@@ -1,8 +1,13 @@
-
- Entries
-
-
+
+ Entries
+
+
+
NO ENTRIES
@@ -16,3 +21,34 @@ const props = defineProps(['entries'])
const entryStore = useEntryStore()
+
+
diff --git a/src/layouts/MainMenu.vue b/src/layouts/MainMenu.vue
index 75ff8de4..7dd5001c 100644
--- a/src/layouts/MainMenu.vue
+++ b/src/layouts/MainMenu.vue
@@ -9,18 +9,57 @@
+
+
+
+
+ Role Updated
+
+
+ Your role has been updated. Please log out and log in again.
+
+
+
+
+
+
diff --git a/src/pages/AdminPage.vue b/src/pages/admin/AdminIndex.vue
similarity index 60%
rename from src/pages/AdminPage.vue
rename to src/pages/admin/AdminIndex.vue
index e9eb2cb9..291ced2b 100644
--- a/src/pages/AdminPage.vue
+++ b/src/pages/admin/AdminIndex.vue
@@ -32,30 +32,47 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
+
-
-
-
-
+
+
@@ -64,16 +81,14 @@
+
+
diff --git a/src/pages/admin/FeedbacksIndex.vue b/src/pages/admin/FeedbacksIndex.vue
new file mode 100644
index 00000000..859affa3
--- /dev/null
+++ b/src/pages/admin/FeedbacksIndex.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/src/pages/admin/PromptsIndex.vue b/src/pages/admin/PromptsIndex.vue
new file mode 100644
index 00000000..eb2d0793
--- /dev/null
+++ b/src/pages/admin/PromptsIndex.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/src/pages/admin/ReportsIndex.vue b/src/pages/admin/ReportsIndex.vue
new file mode 100644
index 00000000..2e6110c2
--- /dev/null
+++ b/src/pages/admin/ReportsIndex.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/src/pages/admin/UsersIndex.vue b/src/pages/admin/UsersIndex.vue
new file mode 100644
index 00000000..21581f2f
--- /dev/null
+++ b/src/pages/admin/UsersIndex.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/src/pages/profile/FeedbackIndex.vue b/src/pages/profile/FeedbackIndex.vue
new file mode 100644
index 00000000..d2cd3319
--- /dev/null
+++ b/src/pages/profile/FeedbackIndex.vue
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/src/pages/ProfilePage.vue b/src/pages/profile/ProfileIndex.vue
similarity index 51%
rename from src/pages/ProfilePage.vue
rename to src/pages/profile/ProfileIndex.vue
index 8e3d0de3..b55562ba 100644
--- a/src/pages/ProfilePage.vue
+++ b/src/pages/profile/ProfileIndex.vue
@@ -7,32 +7,22 @@
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -50,10 +40,8 @@ import { ref } from 'vue'
const userStore = useUserStore()
const user = ref(userStore.getUser)
-const tab = ref(userStore.getProfileTab)
userStore.$subscribe((_mutation, state) => {
user.value = state._user
- tab.value = state._profileTab
})
diff --git a/src/pages/profile/ProfileTab.vue b/src/pages/profile/ProfileTab.vue
new file mode 100644
index 00000000..f5d1d9cc
--- /dev/null
+++ b/src/pages/profile/ProfileTab.vue
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/src/pages/profile/SettingsIndex.vue b/src/pages/profile/SettingsIndex.vue
new file mode 100644
index 00000000..a29d968a
--- /dev/null
+++ b/src/pages/profile/SettingsIndex.vue
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/src/pages/profile/SubscriptionsIndex.vue b/src/pages/profile/SubscriptionsIndex.vue
new file mode 100644
index 00000000..9ca50935
--- /dev/null
+++ b/src/pages/profile/SubscriptionsIndex.vue
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/src/router/admin.js b/src/router/admin.js
new file mode 100644
index 00000000..d899d886
--- /dev/null
+++ b/src/router/admin.js
@@ -0,0 +1,57 @@
+import { useUserStore } from 'stores'
+
+export default [
+ {
+ path: '/admin',
+ name: 'admin',
+ beforeEnter: (_to, _from, next) => {
+ const userStore = useUserStore()
+ if (userStore.isWriterOrAbove) next()
+ else next('/')
+ },
+ redirect: { path: 'admin/prompts' },
+ component: () => import('pages/admin/AdminIndex.vue'),
+ children: [
+ {
+ path: 'prompts',
+ component: () => import('pages/admin/PromptsIndex.vue')
+ },
+ {
+ path: 'users',
+ component: () => import('pages/admin/UsersIndex.vue'),
+ beforeEnter: (_to, _from, next) => {
+ const userStore = useUserStore()
+ if (userStore.isAdmin) next()
+ else next('/')
+ }
+ },
+ {
+ path: 'feedbacks',
+ component: () => import('pages/admin/FeedbacksIndex.vue'),
+ beforeEnter: (_to, _from, next) => {
+ const userStore = useUserStore()
+ if (userStore.isEditorOrAbove) next()
+ else next('/')
+ }
+ },
+ {
+ path: 'errors',
+ component: () => import('pages/admin/ErrorsIndex.vue'),
+ beforeEnter: (_to, _from, next) => {
+ const userStore = useUserStore()
+ if (userStore.isAdmin) next()
+ else next('/')
+ }
+ },
+ {
+ path: 'reports',
+ component: () => import('pages/admin/ReportsIndex.vue'),
+ beforeEnter: (_to, _from, next) => {
+ const userStore = useUserStore()
+ if (userStore.isEditorOrAbove) next()
+ else next('/')
+ }
+ }
+ ]
+ }
+]
diff --git a/src/router/profile.js b/src/router/profile.js
new file mode 100644
index 00000000..8dfdb7db
--- /dev/null
+++ b/src/router/profile.js
@@ -0,0 +1,30 @@
+export default [
+ {
+ path: 'profile',
+ component: () => import('pages/profile/ProfileIndex.vue'),
+ name: 'profile',
+ redirect: { name: 'profile.index' },
+ children: [
+ {
+ name: 'profile.index',
+ path: '',
+ component: () => import('pages/profile/ProfileTab.vue')
+ },
+ {
+ name: 'profile.subscriptions',
+ path: 'subscriptions',
+ component: () => import('pages/profile/SubscriptionsIndex.vue')
+ },
+ {
+ name: 'profile.feedback',
+ path: 'feedback',
+ component: () => import('pages/profile/FeedbackIndex.vue')
+ },
+ {
+ name: 'profile.settings',
+ path: 'settings',
+ component: () => import('pages/profile/SettingsIndex.vue')
+ }
+ ]
+ }
+]
diff --git a/src/router/routes.js b/src/router/routes.js
index 650a9be2..8e1244a8 100644
--- a/src/router/routes.js
+++ b/src/router/routes.js
@@ -1,5 +1,5 @@
-import { useUserStore } from 'stores'
-
+import profile from './profile'
+import admin from './admin'
const routes = [
{
path: '/robots.txt',
@@ -56,19 +56,8 @@ const routes = [
path: 'fan/:username',
component: () => import('pages/PublicProfilePage.vue')
},
- {
- path: 'profile',
- component: () => import('pages/ProfilePage.vue')
- },
- {
- path: 'admin',
- component: () => import('pages/AdminPage.vue'),
- beforeEnter: (_to, _from, next) => {
- const userStore = useUserStore()
- if (userStore.isWriterOrAbove) next()
- else next('/')
- }
- }
+ ...profile,
+ ...admin
]
},
{
diff --git a/src/stores/comments.js b/src/stores/comments.js
index 37b029b2..e84be359 100644
--- a/src/stores/comments.js
+++ b/src/stores/comments.js
@@ -176,7 +176,8 @@ export const useCommentStore = defineStore('comments', {
transaction.update(doc(db, collectionName, documentId, 'comments', commentId), {
author: userStore.getUserIpHash,
isAnonymous: true,
- text: 'Comment Deleted'
+ text: 'Comment Deleted',
+ isDeleted: true
})
}).finally(() => (this._isLoading = false))
},
@@ -210,6 +211,10 @@ export const useCommentStore = defineStore('comments', {
this._isLoading = true
await deleteDoc(doc(db, collectionName, documentId, 'comments', commentId)).finally(() => (this._isLoading = false))
+ },
+
+ async resetComments() {
+ this._comments = undefined
}
}
})
diff --git a/src/stores/entries.js b/src/stores/entries.js
index 87b7c37e..0e769c45 100644
--- a/src/stores/entries.js
+++ b/src/stores/entries.js
@@ -33,7 +33,8 @@ export const useEntryStore = defineStore('entries', {
_entries: undefined,
_isLoading: false,
_unSubscribe: undefined,
- _tab: 'post'
+ _tab: 'post',
+ entryDialog: {}
}),
persist: true,
diff --git a/src/stores/index.js b/src/stores/index.js
index 3fb80486..8ede81be 100644
--- a/src/stores/index.js
+++ b/src/stores/index.js
@@ -6,6 +6,7 @@ import { useCommentStore } from './comments'
import { useEntryStore } from './entries'
import { useErrorStore } from './errors'
import { useFeedbackStore } from './feedbacks'
+import { useReportStore } from './reports'
import { useLikeStore } from './likes'
import { useNotificationStore } from './notifications'
import { usePromptStore } from './prompts'
@@ -54,6 +55,7 @@ export {
useEntryStore,
useErrorStore,
useFeedbackStore,
+ useReportStore,
useLikeStore,
useNotificationStore,
usePromptStore,
diff --git a/src/stores/likes.js b/src/stores/likes.js
index 5a98eab4..54c25293 100644
--- a/src/stores/likes.js
+++ b/src/stores/likes.js
@@ -29,8 +29,6 @@ export const useLikeStore = defineStore('likes', {
if (this._unSubscribeLike || this._unSubscribeDislike) {
this._unSubscribeLike()
this._unSubscribeDislike()
- this._likes = undefined
- this._dislikes = undefined
}
this._unSubscribeLike = onSnapshot(likesCollection, (likesSnapshot) => {
this._likes = likesSnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }))
@@ -112,6 +110,11 @@ export const useLikeStore = defineStore('likes', {
await deleteDoc(doc.ref)
})
this._isLoading = false
+ },
+
+ async resetLikes() {
+ this._likes = undefined
+ this._dislikes = undefined
}
}
})
diff --git a/src/stores/prompts.js b/src/stores/prompts.js
index ef3bab9b..7585ce92 100644
--- a/src/stores/prompts.js
+++ b/src/stores/prompts.js
@@ -17,7 +17,9 @@ export const usePromptStore = defineStore('prompts', {
state: () => ({
_isLoading: false,
_prompts: undefined,
- _tab: 'post'
+ _tab: 'post',
+ promptDialog: false,
+ entryDialog: {}
}),
persist: true,
diff --git a/src/stores/reports.js b/src/stores/reports.js
new file mode 100644
index 00000000..766edd6c
--- /dev/null
+++ b/src/stores/reports.js
@@ -0,0 +1,111 @@
+import { collection, deleteDoc, doc, getDoc, onSnapshot, updateDoc, Timestamp, setDoc } from 'firebase/firestore'
+import { defineStore } from 'pinia'
+import { db } from 'src/firebase'
+import { useUserStore } from './user'
+import { useCommentStore } from './comments'
+
+export const useReportStore = defineStore('reports', {
+ state: () => ({
+ _reports: undefined,
+ _isLoading: false,
+ _unSubscribe: undefined
+ }),
+
+ getters: {
+ getReports: (state) => state._reports,
+ isLoading: (state) => state._isLoading,
+ isLoaded: (state) => !!state._reports
+ },
+
+ actions: {
+ async fetchReports() {
+ this._isLoading = true
+ const userStore = useUserStore()
+ if (!userStore.getUsers) {
+ await userStore.fetchUsers()
+ }
+
+ if (!this._unSubscribe)
+ this._unSubscribe = onSnapshot(collection(db, 'reports'), async (querySnapshot) => {
+ const reports = querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }))
+
+ for (const report of reports) {
+ if (!report.isAnonymous) {
+ report.author = await getDoc(report.author).then((doc) => doc.data())
+ } else {
+ report.author = userStore.getUserById(report.author.id) || report.author.id
+ }
+ }
+ this.$patch({ _reports: reports })
+ })
+ this._isLoading = false
+ },
+
+ async addReports(payload) {
+ try {
+ const userStore = useUserStore()
+ this._isLoading = true
+ const report = {
+ ...payload,
+ author: userStore.isAuthenticated ? userStore.getUserRef : userStore.getUserIpHash,
+ created: Timestamp.fromDate(new Date()),
+ id: Date.now() + '-' + (userStore.isAuthenticated ? userStore.getUserRef : userStore.getUserIpHash),
+ status: 'New',
+ isAnonymous: !userStore.isAuthenticated
+ }
+ const reportRef = doc(db, 'reports', report.id)
+ await setDoc(reportRef, report)
+ } catch (error) {
+ console.error('Error adding report:', error.message)
+ } finally {
+ this._isLoading = false
+ }
+ },
+
+ async deleteReport(id) {
+ try {
+ this._isLoading = true
+ const reportRef = doc(db, 'reports', id)
+ await deleteDoc(reportRef)
+ } catch (error) {
+ console.error('Error deleting document:', error.message)
+ } finally {
+ this._isLoading = false
+ }
+ },
+
+ async editStatusReport(id) {
+ const reportRef = doc(db, 'reports', id)
+
+ try {
+ const reportSnapshot = await getDoc(reportRef)
+ if (reportSnapshot.exists()) {
+ const updatedTimestamp = Timestamp.fromDate(new Date())
+ await updateDoc(reportRef, {
+ status: 'Deleted',
+ updated: updatedTimestamp
+ })
+ } else {
+ console.error('Document does not exist')
+ }
+ } catch (error) {
+ console.error('Error updating document status:', error.message)
+ } finally {
+ this._isLoading = false
+ }
+ },
+
+ async deleteComment(collectionName, documentId, commentId, reportId) {
+ try {
+ this._isLoading = true
+ const commentStore = useCommentStore()
+ await commentStore.deleteComment(collectionName, documentId, commentId)
+ await this.editStatusReport(reportId)
+ } catch (error) {
+ console.error('Error deleting comment:', error.message)
+ } finally {
+ this._isLoading = false
+ }
+ }
+ }
+})
diff --git a/src/stores/shares.js b/src/stores/shares.js
index a3792d51..2b7114f1 100644
--- a/src/stores/shares.js
+++ b/src/stores/shares.js
@@ -54,6 +54,10 @@ export const useShareStore = defineStore('shares', {
await deleteDoc(doc.ref)
})
this._isLoading = false
+ },
+
+ async resetShares() {
+ this._shares = undefined
}
}
})
diff --git a/src/stores/user.js b/src/stores/user.js
index b1b2cdef..777ba57c 100644
--- a/src/stores/user.js
+++ b/src/stores/user.js
@@ -118,7 +118,13 @@ export const useUserStore = defineStore('user', {
.then(() => Notify.create({ color: 'positive', message: 'Account created successfully' }))
.catch((error) => console.error(error))
})
- .catch((error) => console.error(error))
+ .catch((error) => {
+ if (error.code === 'auth/email-already-in-use') {
+ Notify.create({ type: 'negative', message: 'Email already exists' })
+ } else {
+ Notify.create({ type: 'negative', message: 'Something went wrong, Please try again' })
+ }
+ })
.finally(() => (this._isLoading = false))
},