fix: resolve branding display issues and invitation parsing errors
Fixes #84 - Logo and favicon not displaying on branding page and galleries Fixes #85 - Invitations showing undefined expiresAt causing parseISO errors Changes: - Fix nginx.conf: Add ^~ modifier to /uploads location to prioritize proxy over static file matching - Fix vite.config.ts: Add /uploads proxy for development environment - Fix BrandingPage.tsx: Include logo_url from branding settings instead of expecting it from theme - Fix adminUsers.js: Add transformInvitation() to convert snake_case DB fields to camelCase API response - Fix publicSettings.js: Add branding_hide_powered_by to public settings API response - Update README.md: Mark Multiple Administrators feature as implemented - Bump version to 2.2.1
This commit is contained in:
@@ -248,7 +248,7 @@ These features are currently in beta testing and may have limited functionality
|
||||
| **Face Recognition** | AI-powered face detection to help guests find their photos and create automatic person-based albums | Low | 🔄 Open |
|
||||
| **Gallery Feedback** | Allow guests to like, rate, and comment on photos with admin notifications and moderation | Medium | ✅ Implemented |
|
||||
| **Video Support** | Upload and display videos alongside photos in galleries with streaming support | Low | ✅ Implemented |
|
||||
| **Multiple Administrators** | Support for multiple admin accounts with role-based permissions and activity tracking | Low | 📋 Planned |
|
||||
| **Multiple Administrators** | Support for multiple admin accounts with role-based permissions and activity tracking | Low | ✅ Implemented |
|
||||
| **Filtering & Export Options** | Filter photos by likes, ratings, comments, or favorites. Search by filename. Sort by date, name, size, or rating. Export filtered selections as ZIP or generate Capture One/Lightroom-compatible file lists for professional workflows | Medium | ✅ Implemented |
|
||||
|
||||
**Status Legend:** ✅ Implemented | 🚧 In Progress | 🔄 Open | 📋 Planned
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "picpeak-backend",
|
||||
"version": "1.1.15",
|
||||
"version": "2.2.1",
|
||||
"description": "Backend for PicPeak event photo sharing platform",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -45,6 +45,20 @@ function transformRole(role) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform invitation object from snake_case (DB) to camelCase (API)
|
||||
*/
|
||||
function transformInvitation(invitation) {
|
||||
return {
|
||||
id: invitation.id,
|
||||
email: invitation.email,
|
||||
expiresAt: invitation.expires_at,
|
||||
createdAt: invitation.created_at,
|
||||
roleName: invitation.role_name,
|
||||
invitedBy: invitation.invited_by
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /me/permissions
|
||||
* Get current user's permissions
|
||||
@@ -81,7 +95,7 @@ router.get('/roles', adminAuth, requirePermission('users.view'), handleAsync(asy
|
||||
*/
|
||||
router.get('/invitations', adminAuth, requirePermission('users.view'), handleAsync(async (req, res) => {
|
||||
const invitations = await userManagementService.getPendingInvitations();
|
||||
res.json({ invitations });
|
||||
res.json({ invitations: invitations.map(transformInvitation) });
|
||||
}));
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,7 @@ router.get('/', async (req, res) => {
|
||||
branding_logo_display_header: settingsObject.branding_logo_display_header !== false,
|
||||
branding_logo_display_hero: settingsObject.branding_logo_display_hero !== false,
|
||||
branding_logo_display_mode: settingsObject.branding_logo_display_mode || 'logo_and_text',
|
||||
branding_hide_powered_by: settingsObject.branding_hide_powered_by === true,
|
||||
theme_config: settingsObject.theme_config || null,
|
||||
default_language: settingsObject.general_default_language || 'en',
|
||||
enable_analytics: settingsObject.general_enable_analytics !== false,
|
||||
|
||||
+2
-1
@@ -88,7 +88,8 @@ server {
|
||||
}
|
||||
|
||||
# Uploads serving proxy (logos, favicons, watermarks)
|
||||
location /uploads {
|
||||
# ^~ modifier stops regex matching, ensuring uploads are proxied not served locally
|
||||
location ^~ /uploads {
|
||||
proxy_pass http://backend:3001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "picpeak-frontend",
|
||||
"private": true,
|
||||
"version": "1.1.15",
|
||||
"version": "2.2.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -81,9 +81,8 @@ export const BrandingPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
if (settings) {
|
||||
const formatted = settingsService.formatBrandingSettings(settings);
|
||||
// Don't set logo_url here - it will be synced from theme
|
||||
const { logo_url, ...brandingWithoutLogo } = formatted;
|
||||
setBrandingSettings(prev => ({ ...prev, ...brandingWithoutLogo }));
|
||||
// Include logo_url from branding settings
|
||||
setBrandingSettings(prev => ({ ...prev, ...formatted }));
|
||||
}
|
||||
}, [settings]);
|
||||
|
||||
@@ -91,15 +90,17 @@ export const BrandingPage: React.FC = () => {
|
||||
useEffect(() => {
|
||||
if (themeSettings) {
|
||||
const formatted = settingsService.formatThemeSettings(themeSettings) as ThemeConfig;
|
||||
|
||||
|
||||
if (formatted && Object.keys(formatted).length > 0) {
|
||||
// Use the theme's logo URL as stored in the theme config
|
||||
setCurrentTheme(formatted);
|
||||
setTheme(formatted);
|
||||
|
||||
// Always sync the logo URL from theme to branding settings - theme is source of truth
|
||||
setBrandingSettings(prev => ({ ...prev, logo_url: formatted.logoUrl || '' }));
|
||||
|
||||
|
||||
// Only sync logo URL from theme if it exists there (logo is stored in branding settings)
|
||||
if (formatted.logoUrl) {
|
||||
setBrandingSettings(prev => ({ ...prev, logo_url: formatted.logoUrl }));
|
||||
}
|
||||
|
||||
// Try to identify which preset this matches
|
||||
for (const [key, preset] of Object.entries(GALLERY_THEME_PRESETS)) {
|
||||
if (JSON.stringify(preset.config) === JSON.stringify(formatted)) {
|
||||
|
||||
@@ -36,6 +36,10 @@ const config: VitestUserConfig = {
|
||||
target: 'http://localhost:7101',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/uploads': {
|
||||
target: 'http://localhost:7101',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user