feat: draft mode, admin branding, and workflow improvements
Draft Mode: - Events are created as drafts by default — no email sent until published - Add "Publish & Notify Client" button with confirmation dialog - Draft banner with yellow styling on event details page - Draft filter tab in events list - Gallery middleware blocks public access to draft events - Migration 076 adds is_draft column to events table Admin Draft Preview: - Admins can preview draft galleries via JWT preview token (?preview=) - "View Gallery" link on drafts auto-appends preview token Admin & Login Page Branding: - Admin header uses configured company logo/name from branding settings - Login page shows configured logo instead of hardcoded PicPeak - Respects logo_display_mode (logo_only, text_only, logo_and_text) OG Tag Branding: - DynamicFavicon component updates OG meta tags and page title from branding settings Editable Client Email: - Customer email is now editable after event creation in edit mode Branding Inheritance: - New events inherit hero logo settings (visibility, size, position) from global branding configuration Share Link Full Domain URL: - New getFrontendBaseUrl() utility with DB fallback to general_site_url - Used in email processor and share link service
This commit is contained in:
@@ -40,7 +40,7 @@ export const DynamicFavicon: React.FC = () => {
|
||||
}
|
||||
}, [settings?.branding_favicon_url]);
|
||||
|
||||
// Update document title when company name or tagline changes
|
||||
// Update document title and OG meta tags when company name or tagline changes
|
||||
useEffect(() => {
|
||||
const companyName = settings?.branding_company_name?.trim();
|
||||
const tagline = settings?.branding_company_tagline?.trim();
|
||||
@@ -52,6 +52,33 @@ export const DynamicFavicon: React.FC = () => {
|
||||
} else {
|
||||
document.title = DEFAULT_TITLE;
|
||||
}
|
||||
|
||||
// Update OG meta tags
|
||||
const title = companyName || 'PicPeak';
|
||||
const description = tagline || 'Photo Sharing Platform';
|
||||
|
||||
const updateMeta = (property: string, content: string) => {
|
||||
let meta = document.querySelector(`meta[property="${property}"]`) as HTMLMetaElement | null;
|
||||
if (!meta) {
|
||||
meta = document.createElement('meta');
|
||||
meta.setAttribute('property', property);
|
||||
document.head.appendChild(meta);
|
||||
}
|
||||
meta.content = content;
|
||||
};
|
||||
|
||||
updateMeta('og:title', document.title);
|
||||
updateMeta('og:site_name', title);
|
||||
updateMeta('og:description', description);
|
||||
|
||||
// Also update standard meta description
|
||||
let metaDesc = document.querySelector('meta[name="description"]') as HTMLMetaElement | null;
|
||||
if (!metaDesc) {
|
||||
metaDesc = document.createElement('meta');
|
||||
metaDesc.name = 'description';
|
||||
document.head.appendChild(metaDesc);
|
||||
}
|
||||
metaDesc.content = description;
|
||||
}, [settings?.branding_company_name, settings?.branding_company_tagline]);
|
||||
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user