fix(branding): hide "Powered by PicPeak" on every page, not only the gallery (#999)
branding_hide_powered_by only hid the attribution on the main gallery footer. It stayed visible on the gallery password screen, client access page, Premium layout, admin and customer login, accept-invite and CMS pages — AdminLoginPage rendered it unconditionally with no guard at all, so the setting genuinely did not apply there. Routes those surfaces through one <PoweredBy /> component in components/common that reads the public setting itself (the DynamicFavicon pattern) and renders nothing when white-labeling is on, including while the settings are still loading so a white-labelled instance never flashes the attribution. Also collapses three duplicate translation keys (gallery.poweredBy, adminLogin.poweredBy, customer.login.poweredBy) into a single common.poweredBy, and translates pages that had 'Powered by' hardcoded in English across all 8 locales. Fork-PR workflows were never approved so CI did not run. Verified locally against cf243b44: tsc --noEmit clean, ESLint clean, vitest 124 passed across 24 files, and npm run build succeeds. GalleryLayout.tsx keeps its own inline guard and is not routed through the new component; tracked separately. Co-authored-by: lbossuyt <[email protected]>
This commit is contained in:
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { Card } from './Card';
|
||||
import { Loading } from './Loading';
|
||||
import { PoweredBy } from './PoweredBy';
|
||||
import { cmsService } from '../../services/cms.service';
|
||||
import { usePublicSettings } from '../../hooks/usePublicSettings';
|
||||
import { buildResourceUrl } from '../../utils/url';
|
||||
@@ -132,11 +133,7 @@ export const CMSContentBlock: React.FC<CMSContentBlockProps> = ({ slug, fallback
|
||||
{lang === 'de' ? 'Datenschutz' : 'Privacy Policy'}
|
||||
</Link>
|
||||
</div>
|
||||
{!settings?.branding_hide_powered_by && (
|
||||
<p className="mt-2">
|
||||
Powered by <span className="font-semibold">PicPeak</span>
|
||||
</p>
|
||||
)}
|
||||
<PoweredBy className="mt-2" />
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { usePublicSettings } from '../../hooks/usePublicSettings';
|
||||
|
||||
interface PoweredByProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
// "Powered by PicPeak" footer/login attribution. Reads the setting itself (like
|
||||
// DynamicFavicon) so callers don't repeat the guard; hidden for white-label.
|
||||
export const PoweredBy: React.FC<PoweredByProps> = ({ className, style }) => {
|
||||
const { t } = useTranslation();
|
||||
const { data: settings } = usePublicSettings();
|
||||
|
||||
// Hide while settings are still loading too, otherwise a white-labelled
|
||||
// instance flashes the attribution before branding_hide_powered_by resolves.
|
||||
if (!settings || settings.branding_hide_powered_by) return null;
|
||||
|
||||
return (
|
||||
<p className={className} style={style}>
|
||||
{t('common.poweredBy')} <span className="font-semibold">PicPeak</span>
|
||||
</p>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import { PoweredBy } from '../PoweredBy';
|
||||
import { usePublicSettings } from '../../../hooks/usePublicSettings';
|
||||
|
||||
// stub i18n so the prefix comes back as plain English for the assertions
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => (key === 'common.poweredBy' ? 'Powered by' : key),
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('../../../hooks/usePublicSettings', () => ({
|
||||
usePublicSettings: vi.fn(),
|
||||
}));
|
||||
|
||||
const mockUsePublicSettings = vi.mocked(usePublicSettings);
|
||||
|
||||
const setSettings = (data: Record<string, unknown> | undefined) => {
|
||||
mockUsePublicSettings.mockReturnValue({ data } as never);
|
||||
};
|
||||
|
||||
describe('PoweredBy', () => {
|
||||
beforeEach(() => {
|
||||
mockUsePublicSettings.mockReset();
|
||||
});
|
||||
|
||||
it('renders the "Powered by PicPeak" attribution by default', () => {
|
||||
setSettings({});
|
||||
render(<PoweredBy />);
|
||||
expect(screen.getByText(/Powered by/)).toBeInTheDocument();
|
||||
expect(screen.getByText('PicPeak')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders nothing while settings are still loading (no attribution flash)', () => {
|
||||
setSettings(undefined);
|
||||
const { container } = render(<PoweredBy />);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(screen.queryByText('PicPeak')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders nothing when branding_hide_powered_by is enabled (white-label)', () => {
|
||||
setSettings({ branding_hide_powered_by: true });
|
||||
const { container } = render(<PoweredBy />);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
expect(screen.queryByText('PicPeak')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders when branding_hide_powered_by is explicitly false', () => {
|
||||
setSettings({ branding_hide_powered_by: false });
|
||||
render(<PoweredBy />);
|
||||
expect(screen.getByText('PicPeak')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('forwards className and style to the wrapping paragraph', () => {
|
||||
setSettings({});
|
||||
render(<PoweredBy className="text-xs mt-2" style={{ opacity: 0.5 }} />);
|
||||
const paragraph = screen.getByText('PicPeak').closest('p');
|
||||
expect(paragraph).toHaveClass('text-xs', 'mt-2');
|
||||
expect(paragraph).toHaveStyle({ opacity: '0.5' });
|
||||
});
|
||||
});
|
||||
@@ -29,4 +29,5 @@ export { ProtectionWarning } from './ProtectionWarning';
|
||||
export { ReCaptcha } from './ReCaptcha';
|
||||
export { PasswordGenerator } from './PasswordGenerator';
|
||||
export { MarkdownContent } from './MarkdownContent';
|
||||
export { PoweredBy } from './PoweredBy';
|
||||
export { ConfirmDialogProvider, useConfirm, type ConfirmOptions, type ConfirmVariant } from './ConfirmDialog';
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useInView } from 'react-intersection-observer';
|
||||
|
||||
import type { BaseGalleryLayoutProps } from './BaseGalleryLayout';
|
||||
import type { Photo } from '../../../types';
|
||||
import { AuthenticatedImage } from '../../common';
|
||||
import { AuthenticatedImage, PoweredBy } from '../../common';
|
||||
import { feedbackService } from '../../../services/feedback.service';
|
||||
import { PhotoReactions } from '../PhotoReactions';
|
||||
import { useGuestIdentityOptional } from '../../../contexts/GuestIdentityContext';
|
||||
@@ -598,7 +598,7 @@ export const GalleryPremiumLayout: React.FC<GalleryPremiumLayoutProps> = ({
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="gallery-premium-footer">
|
||||
<p>{t('gallery.poweredBy', 'Powered by PicPeak')}</p>
|
||||
<PoweredBy />
|
||||
<p>© {new Date().getFullYear()} {t('gallery.allRightsReserved', 'All rights reserved')}</p>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -152,7 +152,8 @@
|
||||
"duplicate": "Duplizieren",
|
||||
"showAll": "Alle anzeigen",
|
||||
"confirm": "Bestätigen",
|
||||
"show": "Einblenden"
|
||||
"show": "Einblenden",
|
||||
"poweredBy": "Bereitgestellt von"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Fotokategorie",
|
||||
@@ -936,8 +937,7 @@
|
||||
"socials": "Soziale Netzwerke"
|
||||
},
|
||||
"photosCount_one": "{{count}} Foto",
|
||||
"photosCount_other": "{{count}} Fotos",
|
||||
"poweredBy": "Bereitgestellt von PicPeak"
|
||||
"photosCount_other": "{{count}} Fotos"
|
||||
},
|
||||
"categories": {
|
||||
"title": "Fotokategorien",
|
||||
@@ -3792,7 +3792,6 @@
|
||||
"invalidCredentials": "Ungültige E-Mail oder Passwort",
|
||||
"generalError": "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.",
|
||||
"needHelp": "Hilfe benötigt? Kontakt",
|
||||
"poweredBy": "Bereitgestellt von PicPeak",
|
||||
"devModeHint": "Entwicklungsmodus: E-Mail: [email protected], Passwort: admin123",
|
||||
"mfa": {
|
||||
"title": "Zwei-Faktor-Authentifizierung",
|
||||
@@ -3889,8 +3888,7 @@
|
||||
"adminHint": "Sie suchen das Admin-Panel? Besuchen Sie /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Dein Passwort",
|
||||
"needHelp": "Brauchst du Hilfe?",
|
||||
"poweredBy": "Bereitgestellt von PicPeak"
|
||||
"needHelp": "Brauchst du Hilfe?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Konto einrichten",
|
||||
|
||||
@@ -152,7 +152,8 @@
|
||||
"duplicate": "Duplicate",
|
||||
"showAll": "Show all",
|
||||
"confirm": "Confirm",
|
||||
"show": "Show"
|
||||
"show": "Show",
|
||||
"poweredBy": "Powered by"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Photo Category",
|
||||
@@ -478,7 +479,6 @@
|
||||
},
|
||||
"photosCount_one": "{{count}} photo",
|
||||
"photosCount_other": "{{count}} photos",
|
||||
"poweredBy": "Powered by PicPeak",
|
||||
"photosSelected_one": "{{count}} photo selected",
|
||||
"photosSelected_other": "{{count}} photos selected",
|
||||
"downloadSelected_one": "Download {{count}} photo",
|
||||
@@ -3678,7 +3678,6 @@
|
||||
"invalidCredentials": "Invalid email or password",
|
||||
"generalError": "An error occurred. Please try again.",
|
||||
"needHelp": "Need help? Contact",
|
||||
"poweredBy": "Powered by PicPeak",
|
||||
"devModeHint": "Development Mode: Use email: [email protected], password: admin123",
|
||||
"mfa": {
|
||||
"title": "Two-factor authentication",
|
||||
@@ -3889,8 +3888,7 @@
|
||||
"adminHint": "Looking for the admin panel? Visit /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Your password",
|
||||
"needHelp": "Need help?",
|
||||
"poweredBy": "Powered by PicPeak"
|
||||
"needHelp": "Need help?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Set up your account",
|
||||
|
||||
@@ -119,7 +119,8 @@
|
||||
"select": "Seleccionar",
|
||||
"selected": "Seleccionado",
|
||||
"chunk": "Fragmento",
|
||||
"optional": "opcional"
|
||||
"optional": "opcional",
|
||||
"poweredBy": "Desarrollado por"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Categoría de foto",
|
||||
@@ -2458,7 +2459,6 @@
|
||||
"invalidCredentials": "Correo o contraseña inválidos",
|
||||
"generalError": "Ocurrió un error. Por favor, inténtalo de nuevo.",
|
||||
"needHelp": "¿Necesitas ayuda? Contacta",
|
||||
"poweredBy": "Desarrollado por PicPeak",
|
||||
"devModeHint": "Modo desarrollo: usa [email protected], contraseña: admin123"
|
||||
},
|
||||
"clientAccess": {
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"saveChanges": "Enregistrer les modifications",
|
||||
"resetChanges": "Réinitialiser les modifications",
|
||||
"dismiss": "Ignorer",
|
||||
"discard": "Abandonner"
|
||||
"discard": "Abandonner",
|
||||
"poweredBy": "Propulsé par"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Catégorie de la photo",
|
||||
@@ -334,7 +335,6 @@
|
||||
},
|
||||
"photosCount_one": "{{count}} photo",
|
||||
"photosCount_other": "{{count}} photos",
|
||||
"poweredBy": "Propulsé par PicPeak",
|
||||
"photosSelected_one": "{{count}} photo sélectionnée",
|
||||
"photosSelected_other": "{{count}} photos sélectionnées",
|
||||
"downloadSelected_one": "Télécharger {{count}} photo",
|
||||
@@ -2682,7 +2682,6 @@
|
||||
"invalidCredentials": "E-mail ou mot de passe invalide",
|
||||
"generalError": "Une erreur est survenue. Veuillez réessayer.",
|
||||
"needHelp": "Besoin d'aide ? Contactez",
|
||||
"poweredBy": "Propulsé par PicPeak",
|
||||
"devModeHint": "Mode développement : Utilisez l'e-mail : [email protected], mot de passe : admin123"
|
||||
},
|
||||
"clientAccess": {
|
||||
@@ -2762,8 +2761,7 @@
|
||||
"adminHint": "Vous cherchez le panneau d'administration ? Visitez /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Votre mot de passe",
|
||||
"needHelp": "Besoin d'aide ?",
|
||||
"poweredBy": "Propulsé par PicPeak"
|
||||
"needHelp": "Besoin d'aide ?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Configurer votre compte",
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"saveChanges": "Wijzigingen opslaan",
|
||||
"resetChanges": "Wijzigingen ongedaan maken",
|
||||
"dismiss": "Sluiten",
|
||||
"discard": "Verwerpen"
|
||||
"discard": "Verwerpen",
|
||||
"poweredBy": "Mogelijk gemaakt door"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Fotocategorie",
|
||||
@@ -337,8 +338,7 @@
|
||||
"socials": "Sociale media"
|
||||
},
|
||||
"photosCount_one": "{{count}} foto",
|
||||
"photosCount_other": "{{count}} foto's",
|
||||
"poweredBy": "Mogelijk gemaakt door PicPeak"
|
||||
"photosCount_other": "{{count}} foto's"
|
||||
},
|
||||
"categories": {
|
||||
"title": "Fotocategorieen",
|
||||
@@ -2680,7 +2680,6 @@
|
||||
"invalidCredentials": "Ongeldige e-mail of wachtwoord",
|
||||
"generalError": "Er is een fout opgetreden. Probeer het opnieuw.",
|
||||
"needHelp": "Hulp nodig? Neem contact op met",
|
||||
"poweredBy": "Powered by PicPeak",
|
||||
"devModeHint": "Ontwikkelmodus: Gebruik e-mail: [email protected], wachtwoord: admin123"
|
||||
},
|
||||
"clientAccess": {
|
||||
@@ -2751,8 +2750,7 @@
|
||||
"adminHint": "Op zoek naar het beheerderspaneel? Ga naar /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Je wachtwoord",
|
||||
"needHelp": "Hulp nodig?",
|
||||
"poweredBy": "Mogelijk gemaakt door PicPeak"
|
||||
"needHelp": "Hulp nodig?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Account aanmaken",
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"saveChanges": "Salvar alterações",
|
||||
"resetChanges": "Repor alterações",
|
||||
"dismiss": "Dispensar",
|
||||
"discard": "Descartar"
|
||||
"discard": "Descartar",
|
||||
"poweredBy": "Desenvolvido por"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Categoria da Foto",
|
||||
@@ -345,8 +346,7 @@
|
||||
},
|
||||
"photosCount_many": "{{count}} fotos",
|
||||
"photosCount_one": "{{count}} foto",
|
||||
"photosCount_other": "{{count}} fotos",
|
||||
"poweredBy": "Desenvolvido por PicPeak"
|
||||
"photosCount_other": "{{count}} fotos"
|
||||
},
|
||||
"categories": {
|
||||
"title": "Categorias de Fotos",
|
||||
@@ -2701,7 +2701,6 @@
|
||||
"invalidCredentials": "E-mail ou senha inválidos",
|
||||
"generalError": "Ocorreu um erro. Tente novamente.",
|
||||
"needHelp": "Precisa de ajuda? Contate",
|
||||
"poweredBy": "Distribuído por PicPeak",
|
||||
"devModeHint": "Modo Desenvolvimento: E-mail: [email protected], Senha: admin123"
|
||||
},
|
||||
"clientAccess": {
|
||||
@@ -2784,8 +2783,7 @@
|
||||
"adminHint": "Procurando o painel de administração? Acesse /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Sua senha",
|
||||
"needHelp": "Precisa de ajuda?",
|
||||
"poweredBy": "Desenvolvido por PicPeak"
|
||||
"needHelp": "Precisa de ajuda?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Configure sua conta",
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"saveChanges": "Сохранить изменения",
|
||||
"resetChanges": "Сбросить изменения",
|
||||
"dismiss": "Закрыть",
|
||||
"discard": "Отменить"
|
||||
"discard": "Отменить",
|
||||
"poweredBy": "Работает на"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Категория фото",
|
||||
@@ -353,8 +354,7 @@
|
||||
"photosCount_few": "{{count}} фото",
|
||||
"photosCount_many": "{{count}} фото",
|
||||
"photosCount_one": "{{count}} фото",
|
||||
"photosCount_other": "{{count}} фото",
|
||||
"poweredBy": "Работает на PicPeak"
|
||||
"photosCount_other": "{{count}} фото"
|
||||
},
|
||||
"categories": {
|
||||
"title": "Категории фото",
|
||||
@@ -2731,7 +2731,6 @@
|
||||
"invalidCredentials": "Неверный email или пароль",
|
||||
"generalError": "Произошла ошибка. Попробуйте снова.",
|
||||
"needHelp": "Нужна помощь? Свяжитесь",
|
||||
"poweredBy": "Работает на PicPeak",
|
||||
"devModeHint": "Режим разработки: используйте email: [email protected], пароль: admin123"
|
||||
},
|
||||
"clientAccess": {
|
||||
@@ -2817,8 +2816,7 @@
|
||||
"adminHint": "Ищете админ-панель? Перейдите на /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Ваш пароль",
|
||||
"needHelp": "Нужна помощь?",
|
||||
"poweredBy": "Работает на PicPeak"
|
||||
"needHelp": "Нужна помощь?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Создайте учётную запись",
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
"saveChanges": "Shrani spremembe",
|
||||
"resetChanges": "Ponastavi spremembe",
|
||||
"dismiss": "Zapri",
|
||||
"discard": "Zavrzi"
|
||||
"discard": "Zavrzi",
|
||||
"poweredBy": "Poganja"
|
||||
},
|
||||
"upload": {
|
||||
"photoCategory": "Kategorija fotografije",
|
||||
@@ -334,7 +335,6 @@
|
||||
},
|
||||
"photosCount_one": "{{count}} fotografija",
|
||||
"photosCount_other": "{{count}} fotografij",
|
||||
"poweredBy": "Poganja PicPeak",
|
||||
"photosSelected_one": "Izbrana {{count}} fotografija",
|
||||
"photosSelected_other": "Izbranih {{count}} fotografij",
|
||||
"downloadSelected_one": "Prenesi {{count}} fotografijo",
|
||||
@@ -2671,7 +2671,6 @@
|
||||
"invalidCredentials": "Neveljavna e-pošta ali geslo",
|
||||
"generalError": "Prišlo je do napake. Poskusite znova.",
|
||||
"needHelp": "Potrebujete pomoč? Kontakt",
|
||||
"poweredBy": "Poganja PicPeak",
|
||||
"devModeHint": "Razvojni način: uporabite e-pošto: [email protected], geslo: admin123"
|
||||
},
|
||||
"clientAccess": {
|
||||
@@ -2751,8 +2750,7 @@
|
||||
"adminHint": "Iščete administratorsko ploščo? Obiščite /admin/login.",
|
||||
"emailPlaceholder": "[email protected]",
|
||||
"passwordPlaceholder": "Vaše geslo",
|
||||
"needHelp": "Potrebujete pomoč?",
|
||||
"poweredBy": "Poganja PicPeak"
|
||||
"needHelp": "Potrebujete pomoč?"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Nastavite svoj račun",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useParams, useSearchParams, useNavigate, Link } from 'react-router-dom'
|
||||
import { AlertCircle, Lock } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Card, CardContent, Input, Button, Loading } from '../components/common';
|
||||
import { Card, CardContent, Input, Button, Loading, PoweredBy } from '../components/common';
|
||||
import { useGalleryAuth } from '../contexts';
|
||||
import { useGalleryInfo } from '../hooks/useGallery';
|
||||
import { usePublicSettings } from '../hooks/usePublicSettings';
|
||||
@@ -197,9 +197,7 @@ export const ClientAccessPage: React.FC = () => {
|
||||
{t('legal.datenschutz')}
|
||||
</Link>
|
||||
</div>
|
||||
<p className="text-xs mt-2 text-neutral-500">
|
||||
Powered by <span className="font-semibold">PicPeak</span>
|
||||
</p>
|
||||
<PoweredBy className="text-xs mt-2 text-neutral-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useLocalizedDate } from '../hooks/useLocalizedDate';
|
||||
import { usePublicSettings } from '../hooks/usePublicSettings';
|
||||
|
||||
import { Card, CardContent, Input, Button, ReCaptcha, CMSContentBlock } from '../components/common';
|
||||
import { Card, CardContent, Input, Button, ReCaptcha, CMSContentBlock, PoweredBy } from '../components/common';
|
||||
import { useGalleryAuth, useTheme } from '../contexts';
|
||||
import { useGalleryInfo } from '../hooks/useGallery';
|
||||
import { GalleryView } from '../components/gallery';
|
||||
@@ -386,9 +386,7 @@ export const GalleryPage: React.FC = () => {
|
||||
{t('legal.datenschutz')}
|
||||
</Link>
|
||||
</div>
|
||||
<p className="text-xs mt-2 text-neutral-500">
|
||||
Powered by <span className="font-semibold">PicPeak</span>
|
||||
</p>
|
||||
<PoweredBy className="text-xs mt-2 text-neutral-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -594,9 +592,7 @@ export const GalleryPage: React.FC = () => {
|
||||
{t('legal.datenschutz')}
|
||||
</Link>
|
||||
</div>
|
||||
<p className="text-xs mt-2 text-neutral-500">
|
||||
Powered by <span className="font-semibold">PicPeak</span>
|
||||
</p>
|
||||
<PoweredBy className="text-xs mt-2 text-neutral-500" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Lock, Mail, Eye, EyeOff, AlertCircle, ShieldCheck, KeyRound, ArrowLeft
|
||||
import { toast } from 'react-toastify';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Button, Input, Card, ReCaptcha } from '../../components/common';
|
||||
import { Button, Input, Card, ReCaptcha, PoweredBy } from '../../components/common';
|
||||
import { useAdminAuth } from '../../contexts';
|
||||
import { authService } from '../../services/auth.service';
|
||||
import { isMfaChallenge } from '../../types';
|
||||
@@ -486,9 +486,7 @@ export const AdminLoginPage: React.FC = () => {
|
||||
{settingsData?.branding_support_email || '[email protected]'}
|
||||
</a>
|
||||
</p>
|
||||
<p className="text-xs mt-2" style={{ color: 'var(--color-text, #171717)', opacity: 0.5 }}>
|
||||
{t('adminLogin.poweredBy')}
|
||||
</p>
|
||||
<PoweredBy className="text-xs mt-2" style={{ color: 'var(--color-text, #171717)', opacity: 0.5 }} />
|
||||
</div>
|
||||
|
||||
{/* Development Hint */}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Lock, Mail, Eye, EyeOff, AlertCircle } from 'lucide-react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Button, Input, Card, ReCaptcha } from '../../components/common';
|
||||
import { Button, Input, Card, ReCaptcha, PoweredBy } from '../../components/common';
|
||||
import { useCustomerAuth } from '../../contexts/CustomerAuthContext';
|
||||
import { customerService } from '../../services/customer.service';
|
||||
import { usePublicSettings } from '../../hooks/usePublicSettings';
|
||||
@@ -261,9 +261,7 @@ export const CustomerLoginPage: React.FC = () => {
|
||||
{settingsData?.branding_support_email || '[email protected]'}
|
||||
</a>
|
||||
</p>
|
||||
<p className="text-xs mt-2" style={{ color: 'var(--color-text, #171717)', opacity: 0.5 }}>
|
||||
{t('customer.login.poweredBy', 'Powered by PicPeak')}
|
||||
</p>
|
||||
<PoweredBy className="text-xs mt-2" style={{ color: 'var(--color-text, #171717)', opacity: 0.5 }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { Button, Input, Card, Loading } from '../../components/common';
|
||||
import { Button, Input, Card, Loading, PoweredBy } from '../../components/common';
|
||||
import { useLocalizedDate } from '../../hooks/useLocalizedDate';
|
||||
import { api } from '../../config/api';
|
||||
|
||||
@@ -537,9 +537,7 @@ export const AcceptInvitePage: React.FC = () => {
|
||||
{t('acceptInvitation.signIn')}
|
||||
</a>
|
||||
</p>
|
||||
<p className="text-xs mt-2" style={{ color: 'var(--color-text, #171717)', opacity: 0.5 }}>
|
||||
{t('adminLogin.poweredBy')}
|
||||
</p>
|
||||
<PoweredBy className="text-xs mt-2" style={{ color: 'var(--color-text, #171717)', opacity: 0.5 }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user