Merge in DNS/adguard-home from ADG-8368-typescript-node-18 to master Squashed commit of the following: commit daa288ae0d76178af24595cc807055902e6f09ab Merge:4c89cf7201085d59a6Author: Igor Lobanov <bniwredyc@gmail.com> Date: Mon Jun 10 17:22:20 2024 +0200 merge commit4c89cf7209Author: Ildar Kamalov <ik@adguard.com> Date: Thu Jun 6 13:27:18 2024 +0300 remove install from initial state commitb943f2011fAuthor: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 23:10:55 2024 +0200 frontend production build fix commitcd1be2d66dAuthor: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 20:23:14 2024 +0200 production build quickfix commit7b8ac01fc2Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Wed Jun 5 19:57:31 2024 +0300 all: upd node docker commit02afed66d5Author: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 18:23:12 2024 +0200 changelog fixes commit9c0f736f0cMerge:62c4fbf1ee04775c4fAuthor: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 18:18:29 2024 +0200 merge commit62c4fbf1e3Author: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 16:22:22 2024 +0200 empty line in changelog commit76b1e44a93Author: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 16:20:37 2024 +0200 changelog commitf783e90040Author: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 16:19:13 2024 +0200 filters.js -> filters.ts commit3d4ce6554cAuthor: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 16:18:03 2024 +0200 generated file removed commite35ba58f2aAuthor: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 15:45:21 2024 +0200 rollback unwanted changes commit1f30d4216dAuthor: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 15:27:36 2024 +0200 review fix commit6cd4e44f07Author: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 11:55:39 2024 +0200 missing generated file restoresd commit2ab738b303Author: Igor Lobanov <bniwredyc@gmail.com> Date: Wed Jun 5 11:40:32 2024 +0200 Frontend rewritten in TypeScript, added Node 18 support
169 lines
5.4 KiB
TypeScript
169 lines
5.4 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import cn from 'classnames';
|
|
|
|
import { REPOSITORY, PRIVACY_POLICY_LINK, THEMES } from '../../helpers/constants';
|
|
import { LANGUAGES } from '../../helpers/twosky';
|
|
import i18n from '../../i18n';
|
|
|
|
import Version from './Version';
|
|
import './Footer.css';
|
|
import './Select.css';
|
|
|
|
import { setHtmlLangAttr, setUITheme } from '../../helpers/helpers';
|
|
|
|
import { changeTheme } from '../../actions';
|
|
import { RootState } from '../../initialState';
|
|
|
|
const linksData = [
|
|
{
|
|
href: REPOSITORY.URL,
|
|
name: 'homepage',
|
|
},
|
|
{
|
|
href: PRIVACY_POLICY_LINK,
|
|
name: 'privacy_policy',
|
|
},
|
|
{
|
|
href: REPOSITORY.ISSUES,
|
|
className: 'btn btn-outline-primary btn-sm footer__link--report',
|
|
name: 'report_an_issue',
|
|
},
|
|
];
|
|
|
|
const Footer = () => {
|
|
const { t } = useTranslation();
|
|
const dispatch = useDispatch();
|
|
|
|
const currentTheme = useSelector((state: RootState) => (state.dashboard ? state.dashboard.theme : THEMES.auto));
|
|
const profileName = useSelector((state: RootState) => (state.dashboard ? state.dashboard.name : ''));
|
|
const isLoggedIn = profileName !== '';
|
|
const [currentThemeLocal, setCurrentThemeLocal] = useState(THEMES.auto);
|
|
|
|
const getYear = () => {
|
|
const today = new Date();
|
|
return today.getFullYear();
|
|
};
|
|
|
|
const changeLanguage = (event: any) => {
|
|
const { value } = event.target;
|
|
i18n.changeLanguage(value);
|
|
setHtmlLangAttr(value);
|
|
};
|
|
|
|
const onThemeChange = (value: any) => {
|
|
if (isLoggedIn) {
|
|
dispatch(changeTheme(value));
|
|
} else {
|
|
setUITheme(value);
|
|
setCurrentThemeLocal(value);
|
|
}
|
|
};
|
|
|
|
const renderCopyright = () => (
|
|
<div className="footer__column">
|
|
<div className="footer__copyright">
|
|
{t('copyright')} © {getYear()}{' '}
|
|
<a
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
href="https://link.adtidy.org/forward.html?action=home&from=ui&app=home">
|
|
AdGuard
|
|
</a>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
const renderLinks = (linksData: any) =>
|
|
linksData.map(({ name, href, className = '' }: any) => (
|
|
<a
|
|
key={name}
|
|
href={href}
|
|
className={cn('footer__link', className)}
|
|
target="_blank"
|
|
rel="noopener noreferrer">
|
|
{t(name)}
|
|
</a>
|
|
));
|
|
|
|
const renderThemeButtons = () => {
|
|
const currentValue = isLoggedIn ? currentTheme : currentThemeLocal;
|
|
|
|
const content = {
|
|
auto: {
|
|
desc: t('theme_auto_desc'),
|
|
icon: '#auto',
|
|
},
|
|
dark: {
|
|
desc: t('theme_dark_desc'),
|
|
icon: '#dark',
|
|
},
|
|
light: {
|
|
desc: t('theme_light_desc'),
|
|
icon: '#light',
|
|
},
|
|
};
|
|
|
|
return Object.values(THEMES)
|
|
|
|
.map((theme: any) => (
|
|
<button
|
|
key={theme}
|
|
type="button"
|
|
className="btn btn-sm btn-secondary footer__theme-button"
|
|
onClick={() => onThemeChange(theme)}
|
|
title={content[theme].desc}>
|
|
<svg className={cn('footer__theme-icon', { 'footer__theme-icon--active': currentValue === theme })}>
|
|
<use xlinkHref={content[theme].icon} />
|
|
</svg>
|
|
</button>
|
|
));
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<footer className="footer">
|
|
<div className="container">
|
|
<div className="footer__row">
|
|
<div className="footer__column footer__column--links">{renderLinks(linksData)}</div>
|
|
|
|
<div className="footer__column footer__column--theme">
|
|
<div className="footer__themes">
|
|
<div className="btn-group">{renderThemeButtons()}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="footer__column footer__column--language">
|
|
<select
|
|
className="form-control select select--language"
|
|
value={i18n.language}
|
|
onChange={changeLanguage}>
|
|
{Object.keys(LANGUAGES).map((lang) => (
|
|
<option key={lang} value={lang}>
|
|
{LANGUAGES[lang]}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<div className="footer">
|
|
<div className="container">
|
|
<div className="footer__row">
|
|
{renderCopyright()}
|
|
|
|
<div className="footer__column footer__column--language">
|
|
<Version />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Footer;
|