sms & SMTP
This commit is contained in:
+49
-2
@@ -5,6 +5,7 @@ import type { AuthUser, ContactPreference, PreferredLanguage } from './auth';
|
||||
import { useNotifications, toDisplayNotifications } from './notifications';
|
||||
import type { ServerNotification, DisplayNotification } from './notifications';
|
||||
import { getManualTranslation } from './i18nOverrides';
|
||||
import { AdminLeadsView, AdminCampaignsView, AdminMailConfigView } from './admin/marketing';
|
||||
|
||||
const heroImage = new URL('./assets/hero-interior.png', import.meta.url).href;
|
||||
const cityImage = new URL('./assets/city-panorama.png', import.meta.url).href;
|
||||
@@ -3636,7 +3637,8 @@ function accountStorageKey(suffix: string, user: AuthUser | null): string {
|
||||
|
||||
type AdminTab =
|
||||
| 'dashboard' | 'listings' | 'users' | 'messages' | 'reports' | 'payments'
|
||||
| 'stats' | 'settings' | 'moderation' | 'categories' | 'locations' | 'promotions' | 'forbiddenWords';
|
||||
| 'stats' | 'settings' | 'moderation' | 'categories' | 'locations' | 'promotions' | 'forbiddenWords'
|
||||
| 'leads' | 'campaigns' | 'mailConfig';
|
||||
|
||||
const ADMIN_TAB_META: Record<AdminTab, { title: string; subtitle: string }> = {
|
||||
dashboard: { title: 'Panel administratora', subtitle: 'Zarządzaj ogłoszeniami i użytkownikami serwisu.' },
|
||||
@@ -3652,6 +3654,9 @@ const ADMIN_TAB_META: Record<AdminTab, { title: string; subtitle: string }> = {
|
||||
locations: { title: 'Lokalizacje', subtitle: 'Zarządzaj obsługiwanymi miastami i dzielnicami.' },
|
||||
promotions: { title: 'Banery i promocje', subtitle: 'Zarządzaj banerami reklamowymi i promocjami.' },
|
||||
forbiddenWords: { title: 'Zakazane słowa', subtitle: 'Lista wszystkich niedozwolonych słów używanych przez globalny filtr treści.' },
|
||||
leads: { title: 'Leady', subtitle: 'Baza kontaktów marketingowych i grupy docelowe (dynamiczne segmenty).' },
|
||||
campaigns: { title: 'Kampanie marketingowe', subtitle: 'Twórz i wysyłaj kampanie e-mail oraz SMS do grup docelowych.' },
|
||||
mailConfig: { title: 'Konfiguracja wysyłki', subtitle: 'Ustawienia poczty SMTP i bramki SMS dla kampanii i powiadomień.' },
|
||||
};
|
||||
|
||||
const ADMIN_NAV_ITEMS: { id: AdminTab; icon: string; label: string }[] = [
|
||||
@@ -3660,6 +3665,8 @@ const ADMIN_NAV_ITEMS: { id: AdminTab; icon: string; label: string }[] = [
|
||||
{ id: 'users', icon: 'user', label: 'Użytkownicy' },
|
||||
{ id: 'messages', icon: 'message', label: 'Wiadomości' },
|
||||
{ id: 'reports', icon: 'warning', label: 'Zgłoszenia' },
|
||||
{ id: 'leads', icon: 'user', label: 'Leady' },
|
||||
{ id: 'campaigns', icon: 'mail', label: 'Kampanie marketingowe' },
|
||||
{ id: 'payments', icon: 'credit-card', label: 'Płatności' },
|
||||
{ id: 'stats', icon: 'chart', label: 'Statystyki' },
|
||||
{ id: 'settings', icon: 'gear', label: 'Ustawienia serwisu' },
|
||||
@@ -3667,6 +3674,7 @@ const ADMIN_NAV_ITEMS: { id: AdminTab; icon: string; label: string }[] = [
|
||||
|
||||
const ADMIN_TOOL_ITEMS: { id: AdminTab; icon: string; label: string }[] = [
|
||||
{ id: 'moderation', icon: 'check', label: 'Weryfikacja ogłoszeń' },
|
||||
{ id: 'mailConfig', icon: 'gear', label: 'Konfiguracja wysyłki' },
|
||||
{ id: 'forbiddenWords', icon: 'shield', label: 'Zakazane słowa' },
|
||||
{ id: 'categories', icon: 'list', label: 'Kategorie' },
|
||||
{ id: 'locations', icon: 'pin', label: 'Lokalizacje' },
|
||||
@@ -5028,6 +5036,9 @@ function AdminPage({ onNavigate }: { onNavigate: (view: View) => void }) {
|
||||
{!loading && tab === 'categories' && <AdminPlaceholderCard icon="list" label="Kategorie" />}
|
||||
{!loading && tab === 'locations' && <AdminPlaceholderCard icon="pin" label="Lokalizacje" />}
|
||||
{!loading && tab === 'promotions' && <AdminPlaceholderCard icon="spark" label="Banery i promocje" />}
|
||||
{!loading && tab === 'leads' && <AdminLeadsView Icon={Icon} />}
|
||||
{!loading && tab === 'campaigns' && <AdminCampaignsView Icon={Icon} />}
|
||||
{!loading && tab === 'mailConfig' && <AdminMailConfigView Icon={Icon} />}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -8806,16 +8817,52 @@ function AccountListingsPage({ onNavigate, activeView, onOpenListing }: { onNavi
|
||||
function AccountSettingsPage({ onNavigate, activeView }: { onNavigate: (view: View) => void; activeView: View }) {
|
||||
const { user } = useAuth();
|
||||
const [accountSwitches, setAccountSwitches] = useState([true, true, false, false]);
|
||||
// Indeks 4 ("Oferty promowane i newsletter") to zgoda marketingowa e-mail zapisywana na serwerze.
|
||||
const [mailSwitches, setMailSwitches] = useState([true, true, true, false, false]);
|
||||
const [smsConsent, setSmsConsent] = useState(true);
|
||||
const address = user?.address ?? '';
|
||||
const birthDate = user?.birthDate ?? '';
|
||||
|
||||
// Wczytaj aktualną zgodę marketingową użytkownika (steruje kwalifikacją do kampanii).
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
let active = true;
|
||||
apiFetch<{ emailConsent: boolean; smsConsent: boolean }>('/me/marketing')
|
||||
.then((consent) => {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
setSmsConsent(consent.smsConsent);
|
||||
setMailSwitches((current) => current.map((value, idx) => (idx === 4 ? consent.emailConsent : value)));
|
||||
})
|
||||
.catch(() => {
|
||||
// Brak zgody/sesji - zostawiamy wartości domyślne.
|
||||
});
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [user]);
|
||||
|
||||
const toggleAccountSwitch = (index: number) => {
|
||||
setAccountSwitches((current) => current.map((value, idx) => (idx === index ? !value : value)));
|
||||
};
|
||||
|
||||
const toggleMailSwitch = (index: number) => {
|
||||
setMailSwitches((current) => current.map((value, idx) => (idx === index ? !value : value)));
|
||||
setMailSwitches((current) => {
|
||||
const next = current.map((value, idx) => (idx === index ? !value : value));
|
||||
// Zgodę marketingową e-mail (indeks 4) utrwalamy na serwerze.
|
||||
if (index === 4) {
|
||||
apiFetch('/me/marketing', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ emailConsent: next[4], smsConsent }),
|
||||
}).catch(() => {
|
||||
// Błąd zapisu nie blokuje UI; wartość zostanie zsynchronizowana przy kolejnym wejściu.
|
||||
});
|
||||
}
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user