Add 'frontend/' from commit 'c070c0315d66a44154ab7d9f9ea6c211a15f4dba'

git-subtree-dir: frontend
git-subtree-mainline: 205a3bd14b
git-subtree-split: c070c0315d
This commit is contained in:
2025-01-15 15:24:17 -05:00
318 changed files with 29301 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
import {defineStore} from 'pinia';
import {computed, ref} from "vue";
import {useRouter} from "vue-router";
import {useClient} from "@/plugins/api.js";
import {useSessionStorage} from "@vueuse/core";
import {jwtDecode} from "jwt-decode";
function getClaimsFromToken(token) {
try {
return jwtDecode(token);
} catch (error) {
console.error('Invalid token:', error);
return null;
}
}
export const useAuthStore = defineStore(
'auth',
() => {
const clientApi = useClient()
const router = useRouter()
const accessToken = useSessionStorage('auth-accessToken', undefined)
const refreshToken = useSessionStorage('auth-refreshToken', undefined)
const isAuthenticated = computed(() => !!accessToken.value)
const userId = computed(() => {
const claims = getClaimsFromToken(accessToken.value)
return claims.sub;
})
function updateTokens(data) {
accessToken.value = data.accessToken
refreshToken.value = data.refreshToken
}
function cleanTokens() {
updateTokens({
accessToken: undefined,
refreshToken: undefined,
})
}
async function logout() {
cleanTokens()
await router.push('/')
}
async function login(email, password) {
try {
const response = await clientApi.post(
'api/users/login',
{
email: email,
password: password
})
updateTokens(response.data)
return true
} catch (error) {
console.error(error)
cleanTokens()
return false
}
}
async function loginWithGoogle(accessToken) {
try {
const response = await clientApi.post(
'api/users/login-with-google',
{
token: accessToken
})
updateTokens(response.data)
return true
} catch (error) {
console.error(error)
cleanTokens()
return false
}
}
async function refresh() {
try {
const response = await clientApi.post(
'api/users/refresh',
{
refreshToken: refreshToken
});
updateTokens({
accessToken: response.accessToken,
refreshToken: refreshToken
})
} catch (error) {
console.error(error)
cleanTokens()
}
}
return {accessToken, refreshToken, isAuthenticated, userId, login, loginWithGoogle, logout}
})

View File

@@ -0,0 +1,75 @@
import {defineStore} from 'pinia'
import {useClient} from "@/plugins/api.js";
import {useSessionStorage} from "@vueuse/core";
import {ref, watch} from "vue";
import {useRoute} from "vue-router";
export const useBrandingStore = defineStore(
'branding',
() => {
const currentBrand = ref(undefined)
const loading = ref(false)
const value = useSessionStorage(
'branding',
{},
{writeDefaults: false})
const defaultColors = {
"background": "#f4f4f4",
"error": "#f4f4f4",
"primary": "#f4f4f4",
"secondary": "#f4f4f4",
"surface": "#f4f4f4",
"onBackground": "#000",
"onError": "#000",
"onPrimary": "#000",
"onSecondary": "#000",
"onSurface": "#000",
}
const colors = ref(defaultColors)
const presentationInfos = ref([])
const route = useRoute()
watch(
() => route.params.creator,
async (newCreator, oldCreator) => {
loading.value = true
if (newCreator !== oldCreator) {
if (newCreator !== undefined) {
value.value = await fetchCreatorData(newCreator)
currentBrand.value = newCreator
colors.value = value.value.colors
presentationInfos.value = value.value.presentationInfos
} else {
value.value = {}
currentBrand.value = undefined
colors.value = defaultColors
presentationInfos.value = []
}
}
loading.value = false
}
)
const fetchCreatorData = async (creatorAlias) => {
try {
const client = useClient()
const response = await client.get(`/api/creators/@${creatorAlias}`)
return response.data
} catch (error) {
console.error(`Error fetching content: ${error}`)
}
}
return {
currentBrand,
value,
colors,
loading,
presentationInfos
}
})

View File

@@ -0,0 +1,67 @@
import { useClient } from '@/plugins/api.js';
import { useAuthStore } from '@/stores/authStore.js';
import { useSessionStorage } from '@vueuse/core';
import { defineStore } from 'pinia';
import { computed, watch } from 'vue';
import { useRouter } from 'vue-router';
export const useCreatorProfileStore = defineStore('creator-profile', () => {
const router = useRouter();
const authStore = useAuthStore();
watch(
() => authStore.isAuthenticated,
async (newValue) => {
if (newValue) {
await fetchCurrentCreatorProfile();
if (value.value === undefined) {
await router.push('/');
} else {
await router.push(`/@${value.value.name}`);
}
} else {
value.value = undefined;
}
}
);
const value = useSessionStorage(
'creator-profile',
{},
{ writeDefaults: false }
);
const hasCreator = computed(
() => value.value && Object.getOwnPropertyNames(value.value).length >= 1
);
const client = useClient();
async function fetchCurrentCreatorProfile() {
try {
const creatorResponse = await client.get(`/api/creators/profile`);
value.value = creatorResponse.data;
// TODO: no cache-busting ???
} catch (error) {
value.value = undefined;
}
}
async function ConfigureStripeAccount() {
try {
await client.post(`/api/membership/stripe-account`);
return true;
} catch (error) {
return false;
}
}
return {
creator: value,
hasCreator,
fetchCurrentCreatorProfile,
ConfigureStripeAccount,
};
});

View File

@@ -0,0 +1,24 @@
import { defineStore } from 'pinia'
import {ref} from "vue";
import {useClient} from "@/plugins/api.js";
export const useMessageStore = defineStore('message', () => {
const messageCount = ref(0);
const trackedSubject = ref('');
async function fetchMessageCount(subjectId){
const client = useClient();
try {
let uri = `/api/message-count/${subjectId}`;
const response = await client.get(uri);
messageCount.value = response.data.count;
trackedSubject.value = subjectId;
} catch (error) {
console.error("Failed to fetch messages", error);
}
return messageCount.value;
}
return { messageCount, trackedSubject, fetchMessageCount }
})

View File

@@ -0,0 +1,16 @@
// src/stores/sideBarStore.js
import { computed, ref } from 'vue';
import { defineStore } from 'pinia';
export const useSideBarStore = defineStore('sideBar', () => {
const isOpen = ref(true); // par défaut, le menu est ouvert
const toggle = () => {
isOpen.value = !isOpen.value;
};
// Classe de largeur dynamique pour le contenu principal
const sidebarWidth = computed(() => (isOpen.value ? 'ml-64' : 'ml-16'));
return { isOpen, toggle, sidebarWidth };
});

View File

@@ -0,0 +1,48 @@
import {defineStore} from "pinia";
import {useSessionStorage} from "@vueuse/core";
import {useClient} from "@/plugins/api.js";
import {useAuthStore} from "@/stores/authStore.js";
import {watch, onMounted} from "vue";
export const useSubscriptionStore = defineStore(
'subscription',
() => {
const authStore = useAuthStore()
watch(
() => authStore.isAuthenticated,
async (newValue) => {
if (newValue) {
await loadSubscriptions()
} else {
subscriptions.value = {}
}
})
const subscriptions = useSessionStorage(
'subscription-subscriptions',
{})
function isSubscribeTo(creatorId) {
return !!subscriptions.value[creatorId];
}
async function loadSubscriptions() {
try {
const client = useClient()
const response = await client.get(`/api/membership/active`);
subscriptions.value = response.data.reduce(
(acc, sub) => {
acc[sub.creatorId] = sub;
return acc;
},
{});
} catch (error) {
console.error("Error loading subscriptions:", error);
}
}
return {subscriptions, isSubscribeTo}
});

View File

@@ -0,0 +1,178 @@
import {computed, watch} from 'vue'
import {defineStore} from 'pinia'
import {useAuthStore} from "@/stores/authStore.js";
import {useClient} from "@/plugins/api.js";
import {useSessionStorage} from "@vueuse/core";
export const useUserProfileStore = defineStore(
'user-profile',
() => {
const authStore = useAuthStore()
const authWatcher = watch(
() => authStore.isAuthenticated,
async (newValue) => {
if (newValue) {
await fetchCurrentUserProfile()
} else {
value.value = undefined
}
})
const value = useSessionStorage(
'user-profile',
{},
{writeDefaults: false})
const fullname = computed(() => {
if (value.value) {
const {firstname, lastname} = value.value;
if (firstname && lastname) {
return `${lastname}, ${firstname}`;
} else if (firstname) {
return firstname;
} else if (lastname) {
return lastname;
}
}
return 'n/a';
})
const alias = computed(() => {
if (value.value) {
return value.value.alias || `${value.value.firstname || ''} ${value.value.lastname || ''}`.trim() || 'Anonyme'
}
return 'Anonyme';
})
const portraitUrl = computed(() => {
return value.value && value.value.portraitUrl
? value.value.portraitUrl
: '/images/usersmedia/anonyme/profilepictures/profileAnonymeSquare.png'
})
async function fetchCurrentUserProfile() {
try {
const client = useClient()
const userResponse = await client.get("/api/users/profile");
value.value = userResponse.data
// Cache-busting only if portraitUrl exists
if (value.value.portraitUrl) {
value.value.portraitUrl = `${value.value.portraitUrl}?${Date.now()}`;
}
} catch (error) {
value.value = undefined;
}
}
async function changeFullname(firstname, lastname) {
try {
await client.post(
`/api/users/fullname`,
{
firstname: firstname,
lastname: lastname
})
value.value.firstname = firstname;
value.value.lastname = lastname;
} catch (error) {
console.error(error)
}
}
async function changeAlias(alias) {
try {
await client.post(
`/api/users/alias`,
{
alias: alias
})
value.value.alias = alias;
} catch (error) {
console.error(error)
}
}
async function changeBirthday(birthdate) {
try {
await client.post(
`/api/users/birthdate`,
{
birthdate: birthdate
})
value.value.birthDate = birthdate;
} catch (error) {
console.error(error)
}
}
async function changePhone(phoneNumber) {
try {
await client.post(
`/api/users/phone`,
{
phoneNumber: phoneNumber
})
value.value.phoneNumber = phoneNumber;
} catch (error) {
console.error(error)
}
}
async function changeEmail(email) {
try {
await client.post(
`/api/users/email`,
{
email: email
})
value.value.email = email;
} catch (error) {
console.error(error)
}
}
async function changeAddress(address) {
try {
await client.post(
`/api/users/address`,
{
address: address
})
value.value.address = address;
} catch (error) {
console.error(error)
}
}
async function changePortrait(selectedFile) {
try {
const formData = new FormData();
formData.append('file', selectedFile)
const response = await client.post(
`/api/users/portrait`,
formData)
value.value.portraitUrl = `${response.data.blobUrl}?${Date.now()}` // the Date.now() is for cache-busting
} catch (error) {
console.error(error)
}
}
return {
user: value,
alias,
fullname,
portraitUrl,
changeFullname,
changeAlias,
changeBirthday,
changePhone,
changeEmail,
changeAddress,
changePortrait
}
})