diff --git a/frontend/src/plugins/api.js b/frontend/src/plugins/api.js
index 2f9dcef..e0c564f 100644
--- a/frontend/src/plugins/api.js
+++ b/frontend/src/plugins/api.js
@@ -1,102 +1,93 @@
import axios from 'axios';
-import {useAuthStore} from '@/stores/authStore.js';
+import { useAuthStore } from '@/stores/authStore.js';
export function useClient() {
- if (!import.meta.env.VITE_API_URL) {
- throw new Error('VITE_API_URL is not provided');
+ if (!import.meta.env.VITE_API_URL) {
+ throw new Error('VITE_API_URL is not provided');
+ }
+
+ const client = axios.create({
+ baseURL: import.meta.env.VITE_API_URL,
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ const authStore = useAuthStore();
+
+ // Request interceptor
+ client.interceptors.request.use(async (config) => {
+ // Check if this is the refresh token endpoint
+ const isRefreshEndpoint = config.url?.includes('api/users/refresh');
+
+ // Check if we need to refresh the token
+ if (authStore.isAuthenticated && !isRefreshEndpoint) {
+ try {
+ // If token is expiring soon, start a refresh and WAIT for it to complete
+ if (authStore.isTokenExpiringSoon(authStore.accessToken)) {
+ console.log(`Token is expiring soon, waiting for refresh to complete before continuing request: ${config.method?.toUpperCase()} ${config.url}`);
+ await authStore.refresh();
+ console.log(`Token refresh completed, proceeding with request: ${config.method?.toUpperCase()} ${config.url}`);
+ }
+ } catch (error) {
+ console.error(`Failed to refresh token for: ${config.method?.toUpperCase()} ${config.url}`, error);
+ throw error; // This will cancel the request
+ }
}
- const client = axios.create({
- baseURL: import.meta.env.VITE_API_URL,
- headers: {
- 'Content-Type': 'application/json'
+ if (authStore.isAuthenticated && !isRefreshEndpoint) {
+ config.headers.Authorization = `Bearer ${authStore.accessToken}`;
+ }
+
+ if (config.data instanceof FormData) {
+ console.log(`Data is FormData, removing explicit Content-Type header for: ${config.method?.toUpperCase()} ${config.url}`);
+ delete config.headers['Content-Type'];
+ }
+
+ return config;
+ });
+
+
+ // Response interceptor
+ client.interceptors.response.use(
+ (response) => {
+ return response;
+ },
+ async (error) => {
+ const originalRequest = error.config;
+ console.error(`Response interceptor caught an error for: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}`, error);
+
+ // Prevent retry loops by checking if this is already a retry or a refresh request
+ if (error.response?.status === 401 && !originalRequest._retry && !originalRequest.url.includes('api/users/refresh')) {
+ console.log(`Received 401 error for: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}, attempting token refresh...`);
+ originalRequest._retry = true;
+
+ try {
+ // Use a timeout to prevent hanging indefinitely
+ const refreshTimeout = new Promise((_, reject) => {
+ setTimeout(() => reject(new Error('Token refresh timeout')), 10000); // 10s timeout
+ });
+
+ // Race the refresh against the timeout
+ await Promise.race([authStore.refresh(), refreshTimeout]);
+
+ console.log(`Token refresh successful, retrying original request: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}`);
+ return client(originalRequest);
+ } catch (refreshError) {
+ console.error(`Token refresh failed for: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}, logging out user:`, refreshError);
+ // Let the authStore handle the navigation with returnUrl
+ throw refreshError;
}
- });
+ }
- const authStore = useAuthStore();
+ // If it's a refresh request that failed, or a retry that still failed, give up
+ if (originalRequest.url.includes('api/users/refresh') || originalRequest._retry) {
+ console.log(`Request permanently failed: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}`);
+ }
- // Request interceptor
- client.interceptors.request.use(async (config) => {
- console.log(`Request interceptor triggered for: ${config.method?.toUpperCase()} ${config.url}`);
+ return Promise.reject(error);
+ }
+ );
- // Check if this is the refresh token endpoint
- const isRefreshEndpoint = config.url?.includes('api/users/refresh');
-
- // Check if we need to refresh the token
- if (authStore.isAuthenticated && !isRefreshEndpoint) {
- try {
- console.log(`User is authenticated, checking token for: ${config.method?.toUpperCase()} ${config.url}`);
-
- // If token is expiring soon, start a refresh and WAIT for it to complete
- if (authStore.isTokenExpiringSoon(authStore.accessToken)) {
- console.log(`Token is expiring soon, waiting for refresh to complete before continuing request: ${config.method?.toUpperCase()} ${config.url}`);
- await authStore.refresh();
- console.log(`Token refresh completed, proceeding with request: ${config.method?.toUpperCase()} ${config.url}`);
- }
- } catch (error) {
- console.error(`Failed to refresh token for: ${config.method?.toUpperCase()} ${config.url}`, error);
- throw error; // This will cancel the request
- }
- }
-
- if (authStore.isAuthenticated && !isRefreshEndpoint) {
- console.log(`Setting Authorization header for: ${config.method?.toUpperCase()} ${config.url}`);
- config.headers.Authorization = `Bearer ${authStore.accessToken}`;
- } else if (isRefreshEndpoint) {
- console.log(`Skipping Authorization header for refresh endpoint: ${config.method?.toUpperCase()} ${config.url}`);
- }
-
- if (config.data instanceof FormData) {
- console.log(`Data is FormData, removing explicit Content-Type header for: ${config.method?.toUpperCase()} ${config.url}`);
- delete config.headers['Content-Type'];
- }
-
- return config;
- });
-
-
- // Response interceptor
- client.interceptors.response.use(
- (response) => {
- console.log(`Response received successfully for: ${response.config.method?.toUpperCase()} ${response.config.url}`);
- return response;
- },
- async (error) => {
- const originalRequest = error.config;
- console.error(`Response interceptor caught an error for: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}`, error);
-
- // Prevent retry loops by checking if this is already a retry or a refresh request
- if (error.response?.status === 401 && !originalRequest._retry && !originalRequest.url.includes('api/users/refresh')) {
- console.log(`Received 401 error for: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}, attempting token refresh...`);
- originalRequest._retry = true;
-
- try {
- // Use a timeout to prevent hanging indefinitely
- const refreshTimeout = new Promise((_, reject) => {
- setTimeout(() => reject(new Error('Token refresh timeout')), 10000); // 10s timeout
- });
-
- // Race the refresh against the timeout
- await Promise.race([authStore.refresh(), refreshTimeout]);
-
- console.log(`Token refresh successful, retrying original request: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}`);
- return client(originalRequest);
- } catch (refreshError) {
- console.error(`Token refresh failed for: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}, logging out user:`, refreshError);
- // Let the authStore handle the navigation with returnUrl
- throw refreshError;
- }
- }
-
- // If it's a refresh request that failed, or a retry that still failed, give up
- if (originalRequest.url.includes('api/users/refresh') || originalRequest._retry) {
- console.log(`Request permanently failed: ${originalRequest.method?.toUpperCase()} ${originalRequest.url}`);
- // Don't do anything here, let the refresh error handling work
- }
-
- return Promise.reject(error);
- }
- );
-
- return client;
-}
\ No newline at end of file
+ return client;
+}
diff --git a/frontend/src/stores/authStore.js b/frontend/src/stores/authStore.js
index 3841156..1b1663e 100644
--- a/frontend/src/stores/authStore.js
+++ b/frontend/src/stores/authStore.js
@@ -1,284 +1,283 @@
-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';
-import {formatDuration} from "@/internal_time_ago.js";
+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';
+import { formatDuration } from "@/internal_time_ago.js";
export const useAuthStore = defineStore('auth', () => {
- const clientApi = useClient();
- const router = useRouter();
+ const clientApi = useClient();
+ const router = useRouter();
- const isRefreshing = ref(false);
- let refreshPromise = null;
+ const isRefreshing = ref(false);
+ let refreshPromise = null;
- const accessToken = useSessionStorage('auth-accessToken', undefined);
- const refreshToken = useSessionStorage('auth-refreshToken', undefined);
- const tokenClaims = useSessionStorage('auth-tokenClaims', null, {
- serializer: {
- read: (v) => (v ? JSON.parse(v) : null),
- write: (v) => (v ? JSON.stringify(v) : null)
- }
- });
+ const accessToken = useSessionStorage('auth-accessToken', undefined);
+ const refreshToken = useSessionStorage('auth-refreshToken', undefined);
+ const tokenClaims = useSessionStorage('auth-tokenClaims', null, {
+ serializer: {
+ read: (v) => (v ? JSON.parse(v) : null),
+ write: (v) => (v ? JSON.stringify(v) : null)
+ }
+ });
- const isAuthenticated = computed(() => !!accessToken.value);
- const userId = computed(() => tokenClaims.value?.sub);
+ const isAuthenticated = computed(() => !!accessToken.value);
+ const userId = computed(() => tokenClaims.value?.sub);
- function updateTokens(data) {
- console.log('updateTokens called with response data:', data);
- if (!data?.accessToken || !data?.refreshToken) {
- throw new Error('Invalid token data');
- }
- accessToken.value = data.accessToken;
- refreshToken.value = data.refreshToken;
- const claims = getClaimsFromToken(data.accessToken);
- tokenClaims.value = claims;
- console.log('Tokens updated, user ID:', claims?.sub);
+ function updateTokens(data) {
+ if (!data?.accessToken || !data?.refreshToken) {
+ throw new Error('Invalid token data');
+ }
+ accessToken.value = data.accessToken;
+ refreshToken.value = data.refreshToken;
+ const claims = getClaimsFromToken(data.accessToken);
+ tokenClaims.value = claims;
+ console.log('Tokens updated, user ID:', claims?.sub);
+ }
+
+ function cleanTokens() {
+ console.log('cleanTokens called - clearing stored tokens');
+ accessToken.value = undefined;
+ refreshToken.value = undefined;
+ tokenClaims.value = null;
+ }
+
+ async function logout(redirectTo = '/landing') {
+ console.log('logout called, redirecting to:', redirectTo);
+ try {
+ // Optionally call logout endpoint if you have one
+ // await clientApi.post('api/users/logout');
+ } catch (error) {
+ console.error('Logout failed:', error);
+ } finally {
+ cleanTokens();
+ await router.push(redirectTo);
+ }
+ }
+
+ async function login(email, password) {
+ console.log('login called with email:', email);
+ if (!email || !password) {
+ throw new Error('Email and password are required');
}
- function cleanTokens() {
- console.log('cleanTokens called - clearing stored tokens');
- accessToken.value = undefined;
- refreshToken.value = undefined;
- tokenClaims.value = null;
+ try {
+ const response = await clientApi.post('api/users/login', {
+ email: email.trim(),
+ password: password
+ });
+
+ if (!response.data?.accessToken || !response.data?.refreshToken) {
+ throw new Error('Invalid login response');
+ }
+
+ updateTokens(response.data);
+ console.log('login successful');
+ return true;
+ } catch (error) {
+ console.error('Login failed:', error);
+ cleanTokens();
+ throw error;
+ }
+ }
+
+ async function loginWithGoogle(accessTokenParam) {
+ console.log('loginWithGoogle called');
+ if (!accessTokenParam) {
+ throw new Error('Google access token is required');
}
- async function logout(redirectTo = '/landing') {
- console.log('logout called, redirecting to:', redirectTo);
+ try {
+ const response = await clientApi.post('api/users/login-with-google', {
+ token: accessTokenParam
+ });
+
+ if (!response.data?.accessToken || !response.data?.refreshToken) {
+ throw new Error('Invalid Google login response');
+ }
+
+ updateTokens(response.data);
+ console.log('Google login successful');
+ return true;
+ } catch (error) {
+ console.error('Google login failed:', error);
+ cleanTokens();
+ throw error;
+ }
+ }
+
+ async function loginWithFacebook(authResponse) {
+ console.log('loginWithFacebook called');
+ if (!authResponse?.accessToken) {
+ throw new Error('Facebook access token is required');
+ }
+
+ try {
+ const response = await clientApi.post('api/users/login-with-facebook', {
+ token: authResponse.accessToken
+ });
+
+ if (!response.data?.accessToken || !response.data?.refreshToken) {
+ throw new Error('Invalid Facebook login response');
+ }
+
+ updateTokens(response.data);
+ console.log('Facebook login successful');
+ return true;
+ } catch (error) {
+ console.error('Facebook login failed:', error);
+ cleanTokens();
+ throw error;
+ }
+ }
+
+ async function refresh() {
+ console.log('refresh called');
+
+ if (!refreshToken.value) {
+ cleanTokens(); // Clear tokens first
+ throw new Error('No refresh token available');
+ }
+
+ if (isRefreshing.value && refreshPromise) {
+ console.log('Already refreshing, returning existing refreshPromise');
+ return refreshPromise;
+ }
+
+ try {
+ isRefreshing.value = true;
+ refreshPromise = (async () => {
try {
- // Optionally call logout endpoint if you have one
- // await clientApi.post('api/users/logout');
+ console.log('Sending refresh request...');
+
+ const response = await clientApi.post('api/users/refresh', {
+ refreshToken: refreshToken.value
+ });
+
+ if (!response.data?.accessToken || !response.data?.refreshToken) {
+ throw new Error('Invalid refresh response');
+ }
+
+ updateTokens({
+ accessToken: response.data.accessToken,
+ refreshToken: response.data.refreshToken
+ });
+
+ console.log('Token refresh successful');
+ return true;
} catch (error) {
- console.error('Logout failed:', error);
- } finally {
- cleanTokens();
- await router.push(redirectTo);
+ console.error('Token refresh failed:', error);
+ cleanTokens();
+
+ const currentRoute = router.currentRoute.value;
+ const returnUrl = currentRoute.fullPath;
+
+ // Handle navigation
+ router.push({
+ name: 'login',
+ query: { returnUrl }
+ }).catch(navError => {
+ console.error('Navigation error after token refresh failure:', navError);
+ });
+
+ throw error; // Re-throw to notify callers
}
+ })();
+
+ return await refreshPromise;
+ } catch (error) {
+ throw error;
+ } finally {
+ // Ensure these are always reset, even if an error is thrown
+ isRefreshing.value = false;
+ refreshPromise = null;
+ }
+ }
+
+ function getClaimsFromToken(token) {
+ if (!token) return null;
+ try {
+ return jwtDecode(token);
+ } catch (error) {
+ console.error('Failed to decode token:', error);
+ return null;
+ }
+ }
+
+ function isTokenExpiringSoon(token) {
+ if (!token) {
+ console.log('No token provided, considered expiring soon');
+ return true;
}
- async function login(email, password) {
- console.log('login called with email:', email);
- if (!email || !password) {
- throw new Error('Email and password are required');
- }
-
- try {
- const response = await clientApi.post('api/users/login', {
- email: email.trim(),
- password: password
- });
-
- if (!response.data?.accessToken || !response.data?.refreshToken) {
- throw new Error('Invalid login response');
- }
-
- updateTokens(response.data);
- console.log('login successful');
- return true;
- } catch (error) {
- console.error('Login failed:', error);
- cleanTokens();
- throw error;
- }
+ const claims = getClaimsFromToken(token);
+ if (!claims || !claims.exp) {
+ console.log('No valid claims found, considered expiring soon');
+ return true;
}
- async function loginWithGoogle(accessTokenParam) {
- console.log('loginWithGoogle called');
- if (!accessTokenParam) {
- throw new Error('Google access token is required');
- }
+ const expirationTime = claims.exp * 1000; // Convert to milliseconds
+ const currentTime = Date.now();
+ const fiveMinutesInMs = 2 * 60 * 1000; // 2 minutes for demonstration
- try {
- const response = await clientApi.post('api/users/login-with-google', {
- token: accessTokenParam
- });
+ // Calculate time remaining (can be negative if already expired)
+ const timeRemainingMs = expirationTime - currentTime;
- if (!response.data?.accessToken || !response.data?.refreshToken) {
- throw new Error('Invalid Google login response');
- }
+ // Token is expiring soon if less than 2 minutes remaining or already expired
+ const isExpiring = timeRemainingMs < fiveMinutesInMs;
- updateTokens(response.data);
- console.log('Google login successful');
- return true;
- } catch (error) {
- console.error('Google login failed:', error);
- cleanTokens();
- throw error;
- }
+ // Determine the sign for display purposes
+ const formattedTimeRemaining = timeRemainingMs < 0
+ ? `-${formatDuration(Math.abs(timeRemainingMs))}`
+ : formatDuration(timeRemainingMs);
+
+ if (isExpiring) {
+ console.log(`Token expiration check; is token expired: ${isExpiring}`, {
+ expirationTime: new Date(expirationTime).toLocaleString(),
+ currentTime: new Date(currentTime).toLocaleString(),
+ timeRemaining: formattedTimeRemaining
+ });
}
- async function loginWithFacebook(authResponse) {
- console.log('loginWithFacebook called');
- if (!authResponse?.accessToken) {
- throw new Error('Facebook access token is required');
- }
+ return isExpiring;
+ }
- try {
- const response = await clientApi.post('api/users/login-with-facebook', {
- token: authResponse.accessToken
- });
-
- if (!response.data?.accessToken || !response.data?.refreshToken) {
- throw new Error('Invalid Facebook login response');
- }
-
- updateTokens(response.data);
- console.log('Facebook login successful');
- return true;
- } catch (error) {
- console.error('Facebook login failed:', error);
- cleanTokens();
- throw error;
- }
+ async function changePassword(newPassword) {
+ console.log('changePassword called');
+ if (!isAuthenticated.value) {
+ throw new Error('User must be authenticated to change password');
}
- async function refresh() {
- console.log('refresh called');
-
- if (!refreshToken.value) {
- cleanTokens(); // Clear tokens first
- throw new Error('No refresh token available');
- }
-
- if (isRefreshing.value && refreshPromise) {
- console.log('Already refreshing, returning existing refreshPromise');
- return refreshPromise;
- }
-
- try {
- isRefreshing.value = true;
- refreshPromise = (async () => {
- try {
- console.log('Sending refresh request...');
-
- const response = await clientApi.post('api/users/refresh', {
- refreshToken: refreshToken.value
- });
-
- if (!response.data?.accessToken || !response.data?.refreshToken) {
- throw new Error('Invalid refresh response');
- }
-
- updateTokens({
- accessToken: response.data.accessToken,
- refreshToken: response.data.refreshToken
- });
-
- console.log('Token refresh successful');
- return true;
- } catch (error) {
- console.error('Token refresh failed:', error);
- cleanTokens();
-
- const currentRoute = router.currentRoute.value;
- const returnUrl = currentRoute.fullPath;
-
- // Handle navigation
- router.push({
- name: 'login',
- query: {returnUrl}
- }).catch(navError => {
- console.error('Navigation error after token refresh failure:', navError);
- });
-
- throw error; // Re-throw to notify callers
- }
- })();
-
- return await refreshPromise;
- } catch (error) {
- throw error;
- } finally {
- // Ensure these are always reset, even if an error is thrown
- isRefreshing.value = false;
- refreshPromise = null;
- }
+ if (!newPassword) {
+ throw new Error('New password is required');
}
- function getClaimsFromToken(token) {
- if (!token) return null;
- try {
- return jwtDecode(token);
- } catch (error) {
- console.error('Failed to decode token:', error);
- return null;
- }
+ try {
+ const response = await clientApi.post('api/users/set-password', {
+ newPassword
+ });
+
+ console.log('Password changed successfully');
+ return true;
+ } catch (error) {
+ console.error('Password change failed:', error);
+ throw error;
}
+ }
- function isTokenExpiringSoon(token) {
- console.log('isTokenExpiringSoon called');
-
- if (!token) {
- console.log('No token provided, considered expiring soon');
- return true;
- }
-
- const claims = getClaimsFromToken(token);
- if (!claims || !claims.exp) {
- console.log('No valid claims found, considered expiring soon');
- return true;
- }
-
- const expirationTime = claims.exp * 1000; // Convert to milliseconds
- const currentTime = Date.now();
- const fiveMinutesInMs = 2 * 60 * 1000; // 2 minutes for demonstration
-
- // Calculate time remaining (can be negative if already expired)
- const timeRemainingMs = expirationTime - currentTime;
-
- // Token is expiring soon if less than 2 minutes remaining or already expired
- const isExpiring = timeRemainingMs < fiveMinutesInMs;
-
- // Determine the sign for display purposes
- const formattedTimeRemaining = timeRemainingMs < 0
- ? `-${formatDuration(Math.abs(timeRemainingMs))}`
- : formatDuration(timeRemainingMs);
-
- console.log(`Token expiration check; is token expired: ${isExpiring}`, {
- expirationTime: new Date(expirationTime).toLocaleString(),
- currentTime: new Date(currentTime).toLocaleString(),
- timeRemaining: formattedTimeRemaining
- });
-
- return isExpiring;
- }
-
- async function changePassword(newPassword) {
- console.log('changePassword called');
- if (!isAuthenticated.value) {
- throw new Error('User must be authenticated to change password');
- }
-
- if (!newPassword) {
- throw new Error('New password is required');
- }
-
- try {
- const response = await clientApi.post('api/users/set-password', {
- newPassword
- });
-
- console.log('Password changed successfully');
- return true;
- } catch (error) {
- console.error('Password change failed:', error);
- throw error;
- }
- }
-
- return {
- accessToken,
- refreshToken,
- isAuthenticated,
- userId,
- isRefreshing,
- login,
- loginWithGoogle,
- loginWithFacebook,
- logout,
- refresh,
- isTokenExpiringSoon,
- changePassword
- };
-});
\ No newline at end of file
+ return {
+ accessToken,
+ refreshToken,
+ isAuthenticated,
+ userId,
+ isRefreshing,
+ login,
+ loginWithGoogle,
+ loginWithFacebook,
+ logout,
+ refresh,
+ isTokenExpiringSoon,
+ changePassword
+ };
+});
diff --git a/frontend/src/views/creators/AboutCreator.vue b/frontend/src/views/creators/AboutCreator.vue
index d0526de..cc371b9 100644
--- a/frontend/src/views/creators/AboutCreator.vue
+++ b/frontend/src/views/creators/AboutCreator.vue
@@ -214,11 +214,11 @@ async function fetchAlbumData() {
console.log('in fetchAlbumData()');
if (!brandingStore.value?.id) return;
- albumId.value = brandingStore.value.id;
+ const creatorId = brandingStore.value.id;
try {
// Try to get the album
- const response = await client.get(`/api/albums/${albumId.value}`);
+ const response = await client.get(`/api/albums/${creatorId}`);
if (response.data && response.data.photos) {
// Store original photos for comparison
@@ -230,15 +230,15 @@ async function fetchAlbumData() {
isProcessing: false,
isUploading: false,
}));
+ albumId.value = creatorId;
} else {
// Initialize with empty array instead of empty slots
+ console.log('WOW! You found how to get here! Take a look at the stack!');
photos.value = [];
originalPhotos.value = [];
}
- } catch (error) {
- // Album might not exist yet, which is fine
- console.log("Album might not exist yet:", error);
- // Initialize with empty array instead of empty slots
+ }
+ catch (error) {
photos.value = [];
originalPhotos.value = [];
}
@@ -302,46 +302,48 @@ async function saveChanges() {
videoUrl.value = extractVideoId(editableVideoUrl.value) || "";
// Check for deleted photos
- console.log('originalPhotos', originalPhotos.value);
- console.log('photos', photos.value);
const photosOriginalUrls = photos.value.map(photo => photo.image.originalUrl);
- console.log('photosThumbnailUrls', photosOriginalUrls);
const deletedPhotos = originalPhotos.value.filter(originalPhoto => {
// If the photo URL is not in the current images array, it was deleted
return !photosOriginalUrls.includes(originalPhoto.originalUrl);
});
+ const newImages = photos.value.filter(photo => photo && photo.image && photo.image.originalUrl.startsWith('data:'));
+ console.log('originalPhotos', originalPhotos.value);
+ console.log('photos', photos.value);
console.log('deletedPhotos', deletedPhotos);
+ console.log('newImages', newImages);
// Save album photos if they've changed
if (photos.value.length > 0 || deletedPhotos.length > 0) {
- // Create or update the album
- const albumId = brandingStore.value.id;
+ console.log('We got pending changes');
- try {
- // Try to create the album first (it will fail if it already exists)
- await client.post('/api/albums', {
- albumId: albumId,
- title: `${brandingStore.value.name}'s Album`,
- description: "Photo album for the creator"
- });
- } catch (error) {
- // Album might already exist, which is fine
- console.log("Album might already exist:", error);
+ // Create the Album if we do not have one yet
+ if (albumId.value == null) {
+ console.log('We do not have an album yet')
+ try {
+ await client.post('/api/albums', {
+ albumId: brandingStore.value.id,
+ title: `${brandingStore.value.name}'s Album`,
+ description: "Photo album for the creator"
+ });
+ albumId.value = brandingStore.value.id;
+ } catch (error) {
+ // Album might already exist, which is fine
+ console.log("Couldn't create an Album", error);
+ }
}
// Delete removed photos
for (const photo of deletedPhotos) {
try {
- await client.delete(`/api/albums/${albumId}/photos/${photo.id}`);
+ await client.delete(`/api/albums/${albumId.value}/photos/${photo.id}`);
} catch (error) {
console.error("Error deleting photo:", error);
}
}
// Now add or update photos
- const newImages = photos.value.filter(photo => photo && photo.image && photo.image.originalUrl.startsWith('data:'));
- console.log('newImages', newImages);
for (let i = 0; i < newImages.length; i++) {
const imageData = newImages[i];
console.log('Image Data to be uploaded:', imageData);
@@ -356,7 +358,7 @@ async function saveChanges() {
formData.append('file', file);
- await client.post(`/api/albums/${albumId}/photos`, formData, {
+ await client.post(`/api/albums/${albumId.value}/photos`, formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
diff --git a/frontend/src/views/creators/Album.vue b/frontend/src/views/creators/Album.vue
deleted file mode 100644
index f2255a6..0000000
--- a/frontend/src/views/creators/Album.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-{
- "en": {
- "common": {
- "delete": "Delete"
- },
- "creator": {
- "sections": {
- "album": {
- "title": "Photo Album",
- "image": "Album image"
- }
- }
- }
- },
- "fr": {
- "common": {
- "delete": "Supprimer"
- },
- "creator": {
- "sections": {
- "album": {
- "title": "Album photo",
- "image": "Image de l'album"
- }
- }
- }
- },
- "es": {
- "common": {
- "delete": "Eliminar"
- },
- "creator": {
- "sections": {
- "album": {
- "title": "Álbum de fotos",
- "image": "Imagen del álbum"
- }
- }
- }
- }
-}
-
\ No newline at end of file
diff --git a/frontend/src/views/creators/AlbumEditor.vue b/frontend/src/views/creators/AlbumEditor.vue
index d26af18..8a5f0e9 100644
--- a/frontend/src/views/creators/AlbumEditor.vue
+++ b/frontend/src/views/creators/AlbumEditor.vue
@@ -58,7 +58,7 @@