Adds subscriptions
This commit is contained in:
13
src/main.js
13
src/main.js
@@ -9,17 +9,26 @@ import {createVuetify} from 'vuetify'
|
|||||||
import * as components from 'vuetify/components'
|
import * as components from 'vuetify/components'
|
||||||
import * as directives from 'vuetify/directives'
|
import * as directives from 'vuetify/directives'
|
||||||
import vueGoogleOauth from 'vue3-google-login'
|
import vueGoogleOauth from 'vue3-google-login'
|
||||||
|
import {useSubscriptionStore} from "@/stores/subscriptionStore.js";
|
||||||
|
import {useAuthStore} from "@/stores/authStore.js";
|
||||||
|
import {useUserStore} from "@/stores/userStore.js";
|
||||||
|
|
||||||
const vuetify = createVuetify({
|
const vuetify = createVuetify({
|
||||||
components,
|
components,
|
||||||
directives
|
directives
|
||||||
});
|
});
|
||||||
|
|
||||||
createApp(App)
|
const app = createApp(App)
|
||||||
.use(createPinia())
|
.use(createPinia())
|
||||||
.use(vuetify)
|
.use(vuetify)
|
||||||
.use(router)
|
.use(router)
|
||||||
.use(vueGoogleOauth, {
|
.use(vueGoogleOauth, {
|
||||||
clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,
|
clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,
|
||||||
})
|
})
|
||||||
.mount('#app');
|
|
||||||
|
// this force the creation of the stores
|
||||||
|
const subscriptionStore = useSubscriptionStore()
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
app.mount('#app');
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
import { ref, computed } from 'vue'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
|
|
||||||
export const useCounterStore = defineStore('counter', () => {
|
|
||||||
const count = ref(0)
|
|
||||||
const doubleCount = computed(() => count.value * 2)
|
|
||||||
function increment() {
|
|
||||||
count.value++
|
|
||||||
}
|
|
||||||
|
|
||||||
return { count, doubleCount, increment }
|
|
||||||
})
|
|
||||||
71
src/stores/subscriptionStore.js
Normal file
71
src/stores/subscriptionStore.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import {defineStore} from "pinia";
|
||||||
|
import {useSessionStorage} from "@vueuse/core";
|
||||||
|
import {useClient} from "@/plugins/api.js";
|
||||||
|
import {useAuthStore} from "@/stores/authStore.js";
|
||||||
|
import {watch} from "vue";
|
||||||
|
|
||||||
|
export const useSubscriptionStore = defineStore(
|
||||||
|
'subscription',
|
||||||
|
() => {
|
||||||
|
|
||||||
|
const subscriptions = useSessionStorage(
|
||||||
|
'subscription-subscriptions',
|
||||||
|
{})
|
||||||
|
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
const authWatcher = watch(
|
||||||
|
() => authStore.isAuthenticated,
|
||||||
|
async (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
await loadSubscriptions()
|
||||||
|
} else {
|
||||||
|
subscriptions.value = {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function isSubscribeTo(creatorId) {
|
||||||
|
return !!subscriptions.value[creatorId];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function subscribeTo(creatorId) {
|
||||||
|
try {
|
||||||
|
const client = useClient()
|
||||||
|
const response = await client.post(
|
||||||
|
`/api/creators/${creatorId}/subscribe`
|
||||||
|
);
|
||||||
|
subscriptions.value[creatorId] = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error subscribing to creator", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unsubscribeFrom(creatorId) {
|
||||||
|
try {
|
||||||
|
const client = useClient()
|
||||||
|
const response = await client.post(
|
||||||
|
`/api/creators/${creatorId}/unsubscribe`
|
||||||
|
);
|
||||||
|
delete subscriptions.value[creatorId];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error unsubscribing from creator", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSubscriptions() {
|
||||||
|
try {
|
||||||
|
const client = useClient()
|
||||||
|
const response = await client.get(`/api/subscriptions`);
|
||||||
|
|
||||||
|
subscriptions.value = response.data.reduce(
|
||||||
|
(acc, sub) => {
|
||||||
|
acc[sub.creatorId] = sub;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading subscriptions:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {subscriptions, isSubscribeTo, subscribeTo, unsubscribeFrom}
|
||||||
|
});
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
||||||
alt="Profile Image"
|
alt="Profile Image"
|
||||||
class="ml-2 rounded-full"
|
class="ml-2 rounded-full"
|
||||||
style="width: 48px; height: 48px;">
|
width="48"
|
||||||
|
height="48">
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -40,7 +41,8 @@
|
|||||||
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
:src="'/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'"
|
||||||
alt="Profile Image"
|
alt="Profile Image"
|
||||||
class="ml-2 rounded-full"
|
class="ml-2 rounded-full"
|
||||||
style="width: 48px; height: 48px;">
|
width="48"
|
||||||
|
height="48">
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ let last_id = null
|
|||||||
|
|
||||||
async function load({done}) {
|
async function load({done}) {
|
||||||
try {
|
try {
|
||||||
let uri = `/api/contents/user/${props.creatorId}?page_size=${page_size}`
|
let uri = `/api/contents/creator/${props.creatorId}?page_size=${page_size}`
|
||||||
if (last_id !== null) uri = uri + `&last_id=${last_id}`
|
if (last_id !== null) uri = uri + `&last_id=${last_id}`
|
||||||
|
|
||||||
const response = await client.get(uri)
|
const response = await client.get(uri)
|
||||||
|
|||||||
@@ -66,11 +66,8 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-wrap items-center justify-center mt-2 sm:mt-8 md:mt-4 lg:mt-0 lg:ml-auto space-x-2 sm:space-x-4 ml-">
|
class="flex flex-wrap items-center justify-center mt-2 sm:mt-8 md:mt-4 lg:mt-0 lg:ml-auto space-x-2 sm:space-x-4 ml-">
|
||||||
<AboutYou :creator="creator"></AboutYou>
|
<AboutYou :creator="creator"></AboutYou>
|
||||||
<button class="text-white py-2 px-4 rounded"
|
|
||||||
style="background-color: #333; transition: background-color 0.3s ease;"
|
<subscribe-button :creator="creator"></subscribe-button>
|
||||||
onmouseover="this.style.backgroundColor='#555';" onmouseout="this.style.backgroundColor='#333';">
|
|
||||||
S'ABONNER
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<CreatePostButton :creator="creator"/>
|
<CreatePostButton :creator="creator"/>
|
||||||
|
|
||||||
@@ -85,12 +82,12 @@
|
|||||||
import CreatePostButton from "@/views/contents/CreatePostButton.vue";
|
import CreatePostButton from "@/views/contents/CreatePostButton.vue";
|
||||||
import SizeIndicator from "@/views/tools/SizeIndicator.vue";
|
import SizeIndicator from "@/views/tools/SizeIndicator.vue";
|
||||||
import AboutYou from "@/views/creators/CreatorDescriptionBtn.vue";
|
import AboutYou from "@/views/creators/CreatorDescriptionBtn.vue";
|
||||||
|
import SubscribeButton from "@/views/creators/SubscribeButton.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
creator: {type: Object, required: true},
|
creator: {type: Object, required: true},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function GetActiveSocialNetworkUrls() {
|
function GetActiveSocialNetworkUrls() {
|
||||||
|
|
||||||
const socialNetworks = [];
|
const socialNetworks = [];
|
||||||
|
|||||||
49
src/views/creators/SubscribeButton.vue
Normal file
49
src/views/creators/SubscribeButton.vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<script setup>
|
||||||
|
import {useSubscriptionStore} from "@/stores/subscriptionStore.js";
|
||||||
|
import {computed} from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
creator: {type: Object, required: true},
|
||||||
|
});
|
||||||
|
|
||||||
|
const subscriptionStore = useSubscriptionStore()
|
||||||
|
|
||||||
|
const isSubscribe = computed(() => !subscriptionStore.isSubscribeTo(props.creator.id))
|
||||||
|
|
||||||
|
function subscribeToCreator() {
|
||||||
|
subscriptionStore.subscribeTo(props.creator.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsubscribeFromCreator() {
|
||||||
|
subscriptionStore.unsubscribeFrom(props.creator.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<template v-if="isSubscribe">
|
||||||
|
<v-btn class="action"
|
||||||
|
@click="subscribeToCreator()"
|
||||||
|
style="transition: background-color 0.3s ease;">
|
||||||
|
S'ABONNER
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<v-btn class="action"
|
||||||
|
@click="unsubscribeFromCreator()"
|
||||||
|
style="transition: background-color 0.3s ease;">
|
||||||
|
SE DESABONNER
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.action {
|
||||||
|
@apply py-2 px-4 rounded bg-gray-100 hover:bg-gray-300
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
35
src/views/creators/SubscriptionList.vue
Normal file
35
src/views/creators/SubscriptionList.vue
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<script setup>
|
||||||
|
import {useSubscriptionStore} from "@/stores/subscriptionStore.js";
|
||||||
|
|
||||||
|
const subscriptionStore = useSubscriptionStore()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<template v-if="Object.keys(subscriptionStore.subscriptions).length > 0">
|
||||||
|
<template v-for="subscription in subscriptionStore.subscriptions">
|
||||||
|
|
||||||
|
<RouterLink :to="`/@${subscription.creatorName}`">
|
||||||
|
|
||||||
|
<div class="flex items-center content-center font-sans font-semibold pt-2">
|
||||||
|
<img :src="subscription.creatorPortraitUrl"
|
||||||
|
alt="Profile Image"
|
||||||
|
class="rounded-full mx-2"
|
||||||
|
width="32px"
|
||||||
|
height="32px">
|
||||||
|
|
||||||
|
{{ subscription.creatorName }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</RouterLink>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<slot>
|
||||||
|
<span>Placeholder when there are no subscriptions</span>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</template>
|
||||||
@@ -1,49 +1,23 @@
|
|||||||
<template>
|
<script setup>
|
||||||
|
import SiteMenu from "@/views/main/SiteMenu.vue";
|
||||||
|
import SubscriptionList from "@/views/creators/SubscriptionList.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
<aside class="relative h-full overflow-y-auto custom-scrollbar">
|
<aside class="relative h-full overflow-y-auto custom-scrollbar">
|
||||||
|
|
||||||
<nav class="h-full grid grid-rows-[60px_1fr_auto]">
|
<nav class="h-full grid grid-rows-[60px_1fr_auto]">
|
||||||
<div></div>
|
<div></div>
|
||||||
|
|
||||||
<div class="pt-4 px-4">
|
<div class="pt-4 px-4">
|
||||||
<h2>Subscriptions</h2>
|
<h2>Abonnements</h2>
|
||||||
|
|
||||||
<ul class="space-y">
|
<subscription-list>
|
||||||
<li>
|
<template v-slot:default>
|
||||||
<RouterLink to="/@leffet">
|
<span>Aucun abonnement</span>
|
||||||
<div class="nav-button">
|
</template>
|
||||||
<v-icon class="mx-2">mdi-account</v-icon>
|
</subscription-list>
|
||||||
L'Effet
|
|
||||||
</div>
|
|
||||||
</RouterLink>
|
|
||||||
|
|
||||||
<RouterLink to="/@chloebeaugrand">
|
|
||||||
<div class="nav-button">
|
|
||||||
<v-icon class="mx-2">mdi-account</v-icon>
|
|
||||||
Chloe Beaugrand
|
|
||||||
</div>
|
|
||||||
</RouterLink>
|
|
||||||
|
|
||||||
<RouterLink to="/@guillaumeaime">
|
|
||||||
<div class="nav-button">
|
|
||||||
<v-icon class="mx-2">mdi-account</v-icon>
|
|
||||||
Guillaume Aime
|
|
||||||
</div>
|
|
||||||
</RouterLink>
|
|
||||||
|
|
||||||
<RouterLink to="/@mathieucaron">
|
|
||||||
<div class="nav-button">
|
|
||||||
<v-icon class="mx-2">mdi-account</v-icon>
|
|
||||||
Mathieu Caron
|
|
||||||
</div>
|
|
||||||
</RouterLink>
|
|
||||||
|
|
||||||
<RouterLink to="/@arps">
|
|
||||||
<div class="nav-button">
|
|
||||||
<v-icon class="mx-2">mdi-account</v-icon>
|
|
||||||
ARPS
|
|
||||||
</div>
|
|
||||||
</RouterLink>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="border-t w-full py-10">
|
<div class="border-t w-full py-10">
|
||||||
@@ -54,13 +28,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.nav-button {
|
|
||||||
@apply rounded p-1 m-1 text-gray-800 font-sans;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-button:hover {
|
|
||||||
@apply bg-[#903175] text-gray-200;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@apply font-sans font-bold ml-2;
|
@apply font-sans font-bold ml-2;
|
||||||
@@ -74,8 +41,5 @@ aside {
|
|||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: #903175 #f1f1f1;
|
scrollbar-color: #903175 #f1f1f1;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
</style>
|
||||||
import SiteMenu from "@/views/main/SiteMenu.vue";
|
|
||||||
</script>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user