mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
feat(cabinet): legal footer on login + admin toggle
Adds a legal footer (Public Offer / Privacy / Recurring Payments) under the login card, gated by CABINET_FOOTER_ENABLED (backend endpoint added in bot PR #3011), plus an admin toggle in BrandingTab and ru/en/fa/zh i18n. Footer-only subset of PR #464 — excludes the unrelated storePartnerClickId helper and the version/CHANGELOG churn. Co-authored-by: smediainfo <dev@matrixvpn.top>
This commit is contained in:
46
src/components/LegalFooter.tsx
Normal file
46
src/components/LegalFooter.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Fragment } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface LegalLink {
|
||||
href: string;
|
||||
labelKey: string;
|
||||
fallback: string;
|
||||
}
|
||||
|
||||
const LINKS: LegalLink[] = [
|
||||
{ href: '/offer', labelKey: 'footer.offer', fallback: 'Публичная оферта' },
|
||||
{ href: '/privacy', labelKey: 'footer.privacy', fallback: 'Политика конфиденциальности' },
|
||||
{ href: '/recurrent-payments', labelKey: 'footer.recurrent', fallback: 'Рекуррентные платежи' },
|
||||
];
|
||||
|
||||
interface LegalFooterProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function LegalFooter({ className = '' }: LegalFooterProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<footer
|
||||
className={`flex flex-wrap items-center justify-center gap-x-2.5 gap-y-1 text-center text-[11px] leading-relaxed text-dark-500 ${className}`}
|
||||
>
|
||||
{LINKS.map((link, index) => (
|
||||
<Fragment key={link.href}>
|
||||
{index > 0 && (
|
||||
<span className="text-dark-700" aria-hidden="true">
|
||||
·
|
||||
</span>
|
||||
)}
|
||||
<a
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="transition-colors hover:text-accent-400"
|
||||
>
|
||||
{t(link.labelKey, link.fallback)}
|
||||
</a>
|
||||
</Fragment>
|
||||
))}
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@@ -40,6 +40,11 @@ export function BrandingTab({ accentColor = '#3b82f6' }: BrandingTabProps) {
|
||||
queryFn: brandingApi.getGiftEnabled,
|
||||
});
|
||||
|
||||
const { data: footerEnabled } = useQuery({
|
||||
queryKey: ['footer-enabled'],
|
||||
queryFn: brandingApi.getFooterEnabled,
|
||||
});
|
||||
|
||||
// Mutations
|
||||
const updateBrandingMutation = useMutation({
|
||||
mutationFn: brandingApi.updateName,
|
||||
@@ -88,6 +93,13 @@ export function BrandingTab({ accentColor = '#3b82f6' }: BrandingTabProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const updateFooterMutation = useMutation({
|
||||
mutationFn: (enabled: boolean) => brandingApi.updateFooterEnabled(enabled),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['footer-enabled'] });
|
||||
},
|
||||
});
|
||||
|
||||
const handleLogoUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
@@ -250,6 +262,25 @@ export function BrandingTab({ accentColor = '#3b82f6' }: BrandingTabProps) {
|
||||
disabled={updateGiftMutation.isPending}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between rounded-xl bg-dark-700/30 p-4">
|
||||
<div>
|
||||
<span className="font-medium text-dark-100">
|
||||
{t('admin.settings.legalFooter', 'Юридический футер')}
|
||||
</span>
|
||||
<p className="text-sm text-dark-400">
|
||||
{t(
|
||||
'admin.settings.legalFooterDesc',
|
||||
'Ссылки на оферту/политику/рекурренты внизу страницы входа',
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle
|
||||
checked={footerEnabled ?? true}
|
||||
onChange={() => updateFooterMutation.mutate(!(footerEnabled ?? true))}
|
||||
disabled={updateFooterMutation.isPending}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user