@redneckz/wildless-cms-uni-blocks 0.2.46 → 0.2.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/BenefitsBlock.d.ts +2 -2
- package/dist/Blocks.d.ts +15 -0
- package/dist/Blocks.js +13 -7
- package/dist/Blocks.js.map +1 -1
- package/dist/ContentPage.d.ts +2 -2
- package/dist/ContentPage.js +3 -3
- package/dist/ContentPage.js.map +1 -1
- package/dist/ContentPageContext.d.ts +6 -3
- package/dist/ExchangeRateTile.d.ts +7 -0
- package/dist/ExchangeRateTile.js +32 -0
- package/dist/ExchangeRateTile.js.map +1 -0
- package/dist/Footer/Contacts.d.ts +2 -2
- package/dist/Footer/Footer.d.ts +3 -4
- package/dist/Footer/Footer.js.map +1 -1
- package/dist/Footer/FooterLink.d.ts +2 -2
- package/dist/Footer/Sitemap.d.ts +2 -2
- package/dist/Footer/Sitemap.js +8 -5
- package/dist/Footer/Sitemap.js.map +1 -1
- package/dist/Footer/SocialMedia.d.ts +2 -2
- package/dist/Footer/SocialMedia.js +5 -5
- package/dist/Footer/SocialMedia.js.map +1 -1
- package/dist/Footer/index.d.ts +1 -1
- package/dist/Header/Header.d.ts +2 -2
- package/dist/Header/Header.js +3 -2
- package/dist/Header/Header.js.map +1 -1
- package/dist/Icons/DollarIcon.d.ts +1 -0
- package/dist/Icons/DollarIcon.js +6 -0
- package/dist/Icons/DollarIcon.js.map +1 -0
- package/dist/Icons/EuroIcon.d.ts +1 -0
- package/dist/Icons/EuroIcon.js +6 -0
- package/dist/Icons/EuroIcon.js.map +1 -0
- package/dist/Icons/index.d.ts +17 -16
- package/dist/Icons/index.js +26 -22
- package/dist/Icons/index.js.map +1 -1
- package/dist/Img.js +1 -1
- package/dist/Img.js.map +1 -1
- package/dist/LikeControl.d.ts +2 -2
- package/dist/LikeControl.js.map +1 -1
- package/dist/MobileAppTile.d.ts +8 -0
- package/dist/MobileAppTile.js +9 -0
- package/dist/MobileAppTile.js.map +1 -0
- package/dist/Placeholder.d.ts +3 -1
- package/dist/Placeholder.js +9 -2
- package/dist/Placeholder.js.map +1 -1
- package/dist/ProductBlock.d.ts +2 -2
- package/dist/ProductBlockInner.d.ts +2 -2
- package/dist/ProductBlockInner.js +2 -1
- package/dist/ProductBlockInner.js.map +1 -1
- package/dist/ProductGallery.d.ts +2 -2
- package/dist/ProductGallery.js +3 -3
- package/dist/ProductGallery.js.map +1 -1
- package/dist/ProductTile.d.ts +17 -0
- package/dist/ProductTile.js +27 -0
- package/dist/ProductTile.js.map +1 -0
- package/dist/ProjectSettings.d.ts +18 -0
- package/dist/ProjectSettings.js +30 -0
- package/dist/ProjectSettings.js.map +1 -0
- package/dist/StepsBlock.d.ts +2 -2
- package/dist/StepsBlock.js +7 -3
- package/dist/StepsBlock.js.map +1 -1
- package/dist/Tile.d.ts +2 -2
- package/dist/Tile.js +15 -7
- package/dist/Tile.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +3 -10
- package/dist/ui-kit/SearchBar.d.ts +2 -2
- package/dist/ui-kit/SearchBar.js.map +1 -1
- package/dist/useSitemap.d.ts +3 -0
- package/dist/useSitemap.js +16 -0
- package/dist/useSitemap.js.map +1 -0
- package/dist/utils/joinList.d.ts +1 -0
- package/dist/utils/joinList.js +7 -0
- package/dist/utils/joinList.js.map +1 -0
- package/lib/BenefitsBlock.d.ts +2 -2
- package/lib/Blocks.d.ts +15 -0
- package/lib/Blocks.js +10 -4
- package/lib/Blocks.js.map +1 -1
- package/lib/ContentPage.d.ts +2 -2
- package/lib/ContentPage.js +3 -3
- package/lib/ContentPage.js.map +1 -1
- package/lib/ContentPageContext.d.ts +6 -3
- package/lib/ExchangeRateTile.d.ts +7 -0
- package/lib/ExchangeRateTile.js +30 -0
- package/lib/ExchangeRateTile.js.map +1 -0
- package/lib/Footer/Contacts.d.ts +2 -2
- package/lib/Footer/Footer.d.ts +3 -4
- package/lib/Footer/Footer.js.map +1 -1
- package/lib/Footer/FooterLink.d.ts +2 -2
- package/lib/Footer/Sitemap.d.ts +2 -2
- package/lib/Footer/Sitemap.js +8 -5
- package/lib/Footer/Sitemap.js.map +1 -1
- package/lib/Footer/SocialMedia.d.ts +2 -2
- package/lib/Footer/SocialMedia.js +5 -5
- package/lib/Footer/SocialMedia.js.map +1 -1
- package/lib/Footer/index.d.ts +1 -1
- package/lib/Header/Header.d.ts +2 -2
- package/lib/Header/Header.js +3 -2
- package/lib/Header/Header.js.map +1 -1
- package/lib/Icons/DollarIcon.d.ts +1 -0
- package/lib/Icons/DollarIcon.js +3 -0
- package/lib/Icons/DollarIcon.js.map +1 -0
- package/lib/Icons/EuroIcon.d.ts +1 -0
- package/lib/Icons/EuroIcon.js +3 -0
- package/lib/Icons/EuroIcon.js.map +1 -0
- package/lib/Icons/index.d.ts +17 -16
- package/lib/Icons/index.js +17 -16
- package/lib/Icons/index.js.map +1 -1
- package/lib/Img.js +1 -1
- package/lib/Img.js.map +1 -1
- package/lib/LikeControl.d.ts +2 -2
- package/lib/LikeControl.js.map +1 -1
- package/lib/MobileAppTile.d.ts +8 -0
- package/lib/MobileAppTile.js +7 -0
- package/lib/MobileAppTile.js.map +1 -0
- package/lib/Placeholder.d.ts +3 -1
- package/lib/Placeholder.js +9 -2
- package/lib/Placeholder.js.map +1 -1
- package/lib/ProductBlock.d.ts +2 -2
- package/lib/ProductBlockInner.d.ts +2 -2
- package/lib/ProductBlockInner.js +2 -1
- package/lib/ProductBlockInner.js.map +1 -1
- package/lib/ProductGallery.d.ts +2 -2
- package/lib/ProductGallery.js +3 -3
- package/lib/ProductGallery.js.map +1 -1
- package/lib/ProductTile.d.ts +17 -0
- package/lib/ProductTile.js +25 -0
- package/lib/ProductTile.js.map +1 -0
- package/lib/ProjectSettings.d.ts +18 -0
- package/lib/ProjectSettings.js +28 -0
- package/lib/ProjectSettings.js.map +1 -0
- package/lib/StepsBlock.d.ts +2 -2
- package/lib/StepsBlock.js +7 -3
- package/lib/StepsBlock.js.map +1 -1
- package/lib/Tile.d.ts +2 -2
- package/lib/Tile.js +15 -7
- package/lib/Tile.js.map +1 -1
- package/lib/common.css +1 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.js +4 -2
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +3 -10
- package/lib/ui-kit/SearchBar.d.ts +2 -2
- package/lib/ui-kit/SearchBar.js.map +1 -1
- package/lib/useSitemap.d.ts +3 -0
- package/lib/useSitemap.js +13 -0
- package/lib/useSitemap.js.map +1 -0
- package/lib/utils/joinList.d.ts +1 -0
- package/lib/utils/joinList.js +4 -0
- package/lib/utils/joinList.js.map +1 -0
- package/package.json +3 -2
- package/src/BenefitsBlock.fixture.tsx +34 -0
- package/src/BenefitsBlock.tsx +45 -0
- package/src/Blocks.ts +39 -0
- package/src/ContentPage.fixture.tsx +38 -0
- package/src/ContentPage.page.json +680 -0
- package/src/ContentPage.tsx +83 -0
- package/src/ContentPageContext.tsx +34 -0
- package/src/ContentPageHead.tsx +26 -0
- package/src/ExchangeRateTile.fixture.tsx +11 -0
- package/src/ExchangeRateTile.tsx +80 -0
- package/src/Footer/Contacts.tsx +71 -0
- package/src/Footer/Footer.fixture.tsx +265 -0
- package/src/Footer/Footer.tsx +47 -0
- package/src/Footer/FooterLink.ts +6 -0
- package/src/Footer/HorizontalNavigation.tsx +46 -0
- package/src/Footer/Sitemap.tsx +57 -0
- package/src/Footer/SocialMedia.tsx +46 -0
- package/src/Footer/TextInformation.tsx +50 -0
- package/src/Footer/index.ts +2 -0
- package/src/Header/Header.fixture.tsx +21 -0
- package/src/Header/Header.tsx +55 -0
- package/src/Header/HeaderContent.ts +6 -0
- package/src/Header/HeaderSecondaryMenu.tsx +42 -0
- package/src/Header/HeaderSecondaryMenuButton.tsx +21 -0
- package/src/Header/index.ts +3 -0
- package/src/Header/isSubItemActive.ts +9 -0
- package/src/Header/isTopItemActive.ts +13 -0
- package/src/Icons/ActualBalanceIcon.tsx +202 -0
- package/src/Icons/CalendarIcon.tsx +19 -0
- package/src/Icons/ClockIcon.tsx +212 -0
- package/src/Icons/ComfortableCompIcon.tsx +379 -0
- package/src/Icons/DollarIcon.tsx +12 -0
- package/src/Icons/EmptyWalletIcon.tsx +25 -0
- package/src/Icons/EuroIcon.tsx +12 -0
- package/src/Icons/GridIcon.tsx +9 -0
- package/src/Icons/LoupeIcon.tsx +11 -0
- package/src/Icons/NewDocIcon.tsx +262 -0
- package/src/Icons/OkIcon.tsx +8 -0
- package/src/Icons/PassSendIcon.tsx +250 -0
- package/src/Icons/PercentageSquareIcon.tsx +18 -0
- package/src/Icons/ProfileIcon.tsx +18 -0
- package/src/Icons/SignDocsIcon.tsx +295 -0
- package/src/Icons/TelegramIcon.tsx +8 -0
- package/src/Icons/VKIcon.tsx +10 -0
- package/src/Icons/index.ts +17 -0
- package/src/Img.tsx +22 -0
- package/src/LikeControl.fixture.tsx +5 -0
- package/src/LikeControl.tsx +23 -0
- package/src/MobileAppTile.fixture.tsx +15 -0
- package/src/MobileAppTile.tsx +34 -0
- package/src/Placeholder.fixture.tsx +5 -0
- package/src/Placeholder.tsx +33 -0
- package/src/ProductBlock.fixture.tsx +95 -0
- package/src/ProductBlock.tsx +15 -0
- package/src/ProductBlockInner.tsx +111 -0
- package/src/ProductGallery.fixture.tsx +138 -0
- package/src/ProductGallery.tsx +88 -0
- package/src/ProductTile.fixture.tsx +147 -0
- package/src/ProductTile.tsx +95 -0
- package/src/ProjectSettings.ts +38 -0
- package/src/StepsBlock.fixture.tsx +23 -0
- package/src/StepsBlock.tsx +65 -0
- package/src/Tile.fixture.tsx +124 -0
- package/src/Tile.tsx +89 -0
- package/src/api/LikeAPI.ts +141 -0
- package/src/common.css +39 -0
- package/src/content-page-repository/ContentPageRepository.ts +38 -0
- package/src/content-page-repository/TransformationOptions.ts +4 -0
- package/src/content-page-repository/index.ts +1 -0
- package/src/content-page-repository/mapJSON.spec.ts +28 -0
- package/src/content-page-repository/mapJSON.ts +23 -0
- package/src/content-page-repository/transformContentPage.ts +26 -0
- package/src/content-page-repository/transformMarkdown.ts +10 -0
- package/src/content-page-repository/transformPicture.ts +61 -0
- package/src/cosmos.decorator.tsx +19 -0
- package/src/index.ts +20 -0
- package/src/mergeTopItems.spec.ts +20 -0
- package/src/mergeTopItems.ts +13 -0
- package/src/setup-fixture.ts +49 -0
- package/src/types.ts +94 -0
- package/src/ui-kit/BlockItem.fixture.tsx +5 -0
- package/src/ui-kit/BlockItem.tsx +36 -0
- package/src/ui-kit/Breadcrumb.tsx +26 -0
- package/src/ui-kit/Button.fixture.tsx +113 -0
- package/src/ui-kit/Button.tsx +66 -0
- package/src/ui-kit/HeaderItem.fixture.tsx +8 -0
- package/src/ui-kit/HeaderItem.tsx +25 -0
- package/src/ui-kit/LikeButton.fixture.tsx +6 -0
- package/src/ui-kit/LikeButton.tsx +41 -0
- package/src/ui-kit/Logo.fixture.tsx +5 -0
- package/src/ui-kit/Logo.tsx +35 -0
- package/src/ui-kit/SVG.tsx +32 -0
- package/src/ui-kit/SearchBar.tsx +33 -0
- package/src/ui-kit/TopItem.fixture.tsx +8 -0
- package/src/ui-kit/TopItem.tsx +37 -0
- package/src/useLink.ts +28 -0
- package/src/useSitemap.ts +17 -0
- package/src/utils/joinList.ts +7 -0
- package/src/utils/url.ts +22 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
+
import { Blocks } from './Blocks'; // TODO Lazy load
|
|
3
|
+
import { LikeControl } from './LikeControl';
|
|
4
|
+
import { Placeholder } from './Placeholder';
|
|
5
|
+
import type { BlockDef, ContentPageDef, UniBlockProps } from './types';
|
|
6
|
+
|
|
7
|
+
interface BlockDecoratorProps<VNode> {
|
|
8
|
+
blockClassName: string;
|
|
9
|
+
block: BlockDef;
|
|
10
|
+
render: (props: { blockClassName: string; block: BlockDef }) => VNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type BlockDecorator<VNode = any> = (
|
|
14
|
+
props: BlockDecoratorProps<VNode>,
|
|
15
|
+
index?: number | string,
|
|
16
|
+
) => any;
|
|
17
|
+
|
|
18
|
+
export interface ContentPageProps extends UniBlockProps {
|
|
19
|
+
data: ContentPageDef;
|
|
20
|
+
blockDecorator?: BlockDecorator;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const defaultBlockDecorator: BlockDecorator = ({ blockClassName, block, render }) =>
|
|
24
|
+
render({ blockClassName, block });
|
|
25
|
+
|
|
26
|
+
export const ContentPage = JSX<ContentPageProps>(
|
|
27
|
+
({
|
|
28
|
+
className,
|
|
29
|
+
data: { style: pageStyle, blocks, likeControl, colorPalette = 'pc' },
|
|
30
|
+
context,
|
|
31
|
+
blockDecorator = defaultBlockDecorator,
|
|
32
|
+
}) => {
|
|
33
|
+
return (
|
|
34
|
+
<section className="relative" data-theme={colorPalette}>
|
|
35
|
+
<div className={`grid grid-cols-12 gap-1 ${style2className(pageStyle)} ${className}`}>
|
|
36
|
+
{blocks?.length ? blocks.map(renderBlock) : null}
|
|
37
|
+
</div>
|
|
38
|
+
{likeControl && (
|
|
39
|
+
<div className="flex items-end absolute bottom-0 right-0 h-full pointer-events-none">
|
|
40
|
+
<LikeControl
|
|
41
|
+
className="rounded-tl-lg sticky bottom-0 pointer-events-auto"
|
|
42
|
+
context={context}
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
</section>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
function renderBlock(block: BlockDef, i: number) {
|
|
50
|
+
const { type } = block;
|
|
51
|
+
if (!(type in Blocks)) {
|
|
52
|
+
console.warn(`No block with "${type}" is registered`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const BlockComponent = Blocks[type as keyof typeof Blocks] || Placeholder;
|
|
56
|
+
return blockDecorator(
|
|
57
|
+
{
|
|
58
|
+
blockClassName: style2className(block.style),
|
|
59
|
+
block,
|
|
60
|
+
render: (props) => {
|
|
61
|
+
const { version, content, blocks } = props.block;
|
|
62
|
+
return (
|
|
63
|
+
<BlockComponent
|
|
64
|
+
key={`${type}-${i}`}
|
|
65
|
+
className={props.blockClassName}
|
|
66
|
+
version={version}
|
|
67
|
+
context={context}
|
|
68
|
+
{...content}
|
|
69
|
+
>
|
|
70
|
+
{blocks?.length ? blocks.map(renderBlock) : null}
|
|
71
|
+
</BlockComponent>
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
`block-${i}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
function style2className(style: string[] | undefined | null): string {
|
|
82
|
+
return style ? style.join(' ') : '';
|
|
83
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface Router {
|
|
2
|
+
pathname: string;
|
|
3
|
+
query: Record<string, string | string[] | undefined>;
|
|
4
|
+
href?: string;
|
|
5
|
+
basePath?: string;
|
|
6
|
+
push: (url: string) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface LikeService {
|
|
10
|
+
likeCount: number;
|
|
11
|
+
like: () => void;
|
|
12
|
+
dislike: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type HandlerDecorator = <F extends Function>(handler: F, targetContent: any) => F;
|
|
16
|
+
|
|
17
|
+
export interface Search {
|
|
18
|
+
term: string;
|
|
19
|
+
setTerm: (t: string) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type AsyncDataHook = <Data, Error = any>(
|
|
23
|
+
key: string,
|
|
24
|
+
fetcher: () => Promise<Data>,
|
|
25
|
+
) => { data?: Data; error?: Error };
|
|
26
|
+
|
|
27
|
+
export interface ContentPageContext {
|
|
28
|
+
useRouter: () => Router;
|
|
29
|
+
useState: <State>(initialState: State) => [State, (_: State) => void];
|
|
30
|
+
useAsyncData: AsyncDataHook;
|
|
31
|
+
useLikeService: () => LikeService;
|
|
32
|
+
useSearch: () => Search;
|
|
33
|
+
handlerDecorator?: HandlerDecorator;
|
|
34
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
+
import type { ContentPageMeta } from './types';
|
|
3
|
+
|
|
4
|
+
export interface ContentPageHeadProps {
|
|
5
|
+
HeadComponent: Function;
|
|
6
|
+
data: ContentPageMeta;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const ContentPageHead = JSX<ContentPageHeadProps>(({ HeadComponent, data, children }) => {
|
|
10
|
+
const { title, description, keywords, robots, og } = data;
|
|
11
|
+
return (
|
|
12
|
+
<HeadComponent>
|
|
13
|
+
<title>{title}</title>
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
15
|
+
{description && <meta name="description" content={description} />}
|
|
16
|
+
{keywords && <meta name="keywords" content={keywords.join(',')} />}
|
|
17
|
+
{robots && <meta name="robots" content={robots.join(',')} />}
|
|
18
|
+
{og
|
|
19
|
+
? Object.entries(og).map(([key, value]) => (
|
|
20
|
+
<meta key={key} name={`og:${key}`} content={value} />
|
|
21
|
+
))
|
|
22
|
+
: null}
|
|
23
|
+
{children}
|
|
24
|
+
</HeadComponent>
|
|
25
|
+
);
|
|
26
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
+
import { DollarIcon, EuroIcon } from './Icons/index';
|
|
3
|
+
import { Tile } from './Tile';
|
|
4
|
+
import type { UniBlockProps } from './types';
|
|
5
|
+
import { ButtonProps } from './ui-kit/Button';
|
|
6
|
+
|
|
7
|
+
export interface ExchangeRateTileContent {
|
|
8
|
+
title?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ExchangeRateTileProps extends ExchangeRateTileContent, UniBlockProps {}
|
|
12
|
+
|
|
13
|
+
const CBR_EXCHANGE_RATE_URL = 'https://www.cbr-xml-daily.ru/daily_json.js';
|
|
14
|
+
|
|
15
|
+
const CURRENCY_CODES = ['USD', 'EUR'];
|
|
16
|
+
const CURRENCY_ICONS_MAP = {
|
|
17
|
+
USD: DollarIcon,
|
|
18
|
+
EUR: EuroIcon,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const button: ButtonProps = {
|
|
22
|
+
text: 'Все показатели',
|
|
23
|
+
href: 'https://cbr.ru/currency_base/daily/',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const ExchangeRateTile = JSX<ExchangeRateTileProps>(({ className, context, title }) => {
|
|
27
|
+
const { data } = context.useAsyncData(CBR_EXCHANGE_RATE_URL, fetchExchangeRate);
|
|
28
|
+
return (
|
|
29
|
+
<Tile
|
|
30
|
+
className={className}
|
|
31
|
+
context={context}
|
|
32
|
+
title={title || 'Курсы обмена валют'}
|
|
33
|
+
button={button}
|
|
34
|
+
>
|
|
35
|
+
<table>
|
|
36
|
+
<thead>
|
|
37
|
+
<tr>
|
|
38
|
+
<CurrencyTH>Валюта</CurrencyTH>
|
|
39
|
+
<CurrencyTH className="pl-11">Курс</CurrencyTH>
|
|
40
|
+
</tr>
|
|
41
|
+
</thead>
|
|
42
|
+
<tbody>
|
|
43
|
+
{CURRENCY_CODES.map((code) => {
|
|
44
|
+
const value = (data?.Valute || {})[code]?.Value;
|
|
45
|
+
return (
|
|
46
|
+
<tr key={code}>
|
|
47
|
+
<CurrencyTD className="pt-4">
|
|
48
|
+
<div className="flex items-center">
|
|
49
|
+
{CURRENCY_ICONS_MAP[code] ? CURRENCY_ICONS_MAP[code]() : null}
|
|
50
|
+
<span className="ml-2">{code}</span>
|
|
51
|
+
</div>
|
|
52
|
+
</CurrencyTD>
|
|
53
|
+
<CurrencyTD className="pt-4 pl-11">{formatCurrency(value)}</CurrencyTD>
|
|
54
|
+
</tr>
|
|
55
|
+
);
|
|
56
|
+
})}
|
|
57
|
+
</tbody>
|
|
58
|
+
</table>
|
|
59
|
+
</Tile>
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const CurrencyTH = JSX<{ className?: string }>(({ className = '', children }) => (
|
|
64
|
+
<th className={`text-left font-normal text-sm text-secondary-text ${className}`}>{children}</th>
|
|
65
|
+
));
|
|
66
|
+
|
|
67
|
+
const CurrencyTD = JSX<{ className?: string }>(({ className = '', children }) => (
|
|
68
|
+
<td className={`text-left font-normal text-base text-primary-text ${className}`}>{children}</td>
|
|
69
|
+
));
|
|
70
|
+
|
|
71
|
+
async function fetchExchangeRate(): Promise<{
|
|
72
|
+
Valute?: Record<string, { CharCode: string; Name?: string; Value: number; Previous?: number }>;
|
|
73
|
+
}> {
|
|
74
|
+
const response = await fetch(CBR_EXCHANGE_RATE_URL);
|
|
75
|
+
return await response.json();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const currencyNumberFormat = new Intl.NumberFormat('ru', { style: 'currency', currency: 'RUB' });
|
|
79
|
+
|
|
80
|
+
const formatCurrency = (value?: number) => (value ? currencyNumberFormat.format(value) : '');
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
+
import type { UniBlockProps, ContactInfo } from '../types';
|
|
3
|
+
import { Button } from '../ui-kit/Button';
|
|
4
|
+
import { useLink } from '../useLink';
|
|
5
|
+
|
|
6
|
+
export interface ContactsProps extends UniBlockProps {
|
|
7
|
+
items?: ContactInfo[];
|
|
8
|
+
hasButton?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Contacts = JSX<ContactsProps>(({ className, items, hasButton, context }) => {
|
|
12
|
+
const router = context.useRouter();
|
|
13
|
+
const { handlerDecorator } = context;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={`flex flex-col ${className || ''}`}>
|
|
17
|
+
{items?.length ? items.map(renderContact) : null}
|
|
18
|
+
{hasButton ? (
|
|
19
|
+
<Button
|
|
20
|
+
className="my-4"
|
|
21
|
+
{...useLink(
|
|
22
|
+
{ router, handlerDecorator },
|
|
23
|
+
{
|
|
24
|
+
text: 'Обратная связь',
|
|
25
|
+
href: '/',
|
|
26
|
+
target: '_blank',
|
|
27
|
+
},
|
|
28
|
+
)}
|
|
29
|
+
/>
|
|
30
|
+
) : null}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const renderContact = (item: ContactInfo, index: number) => {
|
|
36
|
+
const { type, text, description } = item;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="mb-4" key={String(index)}>
|
|
40
|
+
<div>{renderText(type, text)}</div>
|
|
41
|
+
<div className="font-sans text-sm text-secondary-text">{description}</div>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const renderText = (type: ContactInfo['type'], text: string) => {
|
|
47
|
+
switch (type) {
|
|
48
|
+
case 'tel':
|
|
49
|
+
return (
|
|
50
|
+
<a
|
|
51
|
+
className="font-sans font-medium text-xl text-primary-text no-underline"
|
|
52
|
+
href={`tel:${formatTel(text)}`}
|
|
53
|
+
>
|
|
54
|
+
{text}
|
|
55
|
+
</a>
|
|
56
|
+
);
|
|
57
|
+
case 'email':
|
|
58
|
+
return (
|
|
59
|
+
<a
|
|
60
|
+
className="font-sans font-medium text-xl text-primary-text no-underline"
|
|
61
|
+
href={`mailto:${text}`}
|
|
62
|
+
>
|
|
63
|
+
{text}
|
|
64
|
+
</a>
|
|
65
|
+
);
|
|
66
|
+
default:
|
|
67
|
+
return <span>{text}</span>;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const formatTel = (s: string) => s.replaceAll(/(\-|\s|\(|\)|\D+)/g, '');
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { context } from '../setup-fixture';
|
|
2
|
+
import { Footer } from './Footer';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_ORIGIN = 'https://rshb.ru/';
|
|
5
|
+
|
|
6
|
+
export default (
|
|
7
|
+
<Footer
|
|
8
|
+
topItems={[
|
|
9
|
+
{
|
|
10
|
+
href: DEFAULT_ORIGIN,
|
|
11
|
+
text: 'Частным клиентам',
|
|
12
|
+
target: '_blank',
|
|
13
|
+
items: [
|
|
14
|
+
{
|
|
15
|
+
href: DEFAULT_ORIGIN,
|
|
16
|
+
text: 'Кредитные карты',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
href: DEFAULT_ORIGIN,
|
|
20
|
+
text: 'Дебетовые карты',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
href: DEFAULT_ORIGIN,
|
|
24
|
+
text: 'Кредиты',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
href: DEFAULT_ORIGIN,
|
|
28
|
+
text: 'Ипотека',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
href: DEFAULT_ORIGIN,
|
|
32
|
+
text: 'Вклады и сбережения',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
href: DEFAULT_ORIGIN,
|
|
36
|
+
text: 'Инвестиции',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
href: DEFAULT_ORIGIN,
|
|
40
|
+
text: 'Страхование',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
href: DEFAULT_ORIGIN,
|
|
44
|
+
text: 'Премиальным клиентам',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
href: DEFAULT_ORIGIN,
|
|
48
|
+
text: 'Биометрическая регистрация',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
href: DEFAULT_ORIGIN,
|
|
52
|
+
text: 'Перевод денег',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
href: DEFAULT_ORIGIN,
|
|
56
|
+
text: 'Обмен денег',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
href: DEFAULT_ORIGIN,
|
|
60
|
+
text: 'Акции',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
href: DEFAULT_ORIGIN,
|
|
64
|
+
text: 'Тарифы',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
href: DEFAULT_ORIGIN,
|
|
68
|
+
text: 'Архивная информация',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
href: DEFAULT_ORIGIN,
|
|
74
|
+
text: 'Бизнес клиентам',
|
|
75
|
+
target: '_blank',
|
|
76
|
+
items: [
|
|
77
|
+
{
|
|
78
|
+
href: DEFAULT_ORIGIN,
|
|
79
|
+
text: 'РКО',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
href: DEFAULT_ORIGIN,
|
|
83
|
+
text: 'Кредиты',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
href: DEFAULT_ORIGIN,
|
|
87
|
+
text: 'Депозиты',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
href: DEFAULT_ORIGIN,
|
|
91
|
+
text: 'Эквайринг',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
href: DEFAULT_ORIGIN,
|
|
95
|
+
text: 'Банковские карты',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
href: DEFAULT_ORIGIN,
|
|
99
|
+
text: 'ВЭД',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
href: DEFAULT_ORIGIN,
|
|
103
|
+
text: 'Инвестиции',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
href: DEFAULT_ORIGIN,
|
|
107
|
+
text: 'Обмен валюты',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
href: DEFAULT_ORIGIN,
|
|
111
|
+
text: 'Страхование',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
href: DEFAULT_ORIGIN,
|
|
115
|
+
text: 'Партнёрские программы',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
href: DEFAULT_ORIGIN,
|
|
119
|
+
text: 'Онлайн-сервисы',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
href: DEFAULT_ORIGIN,
|
|
123
|
+
text: 'Акции',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
href: DEFAULT_ORIGIN,
|
|
127
|
+
text: 'Тарифы',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
href: DEFAULT_ORIGIN,
|
|
131
|
+
text: 'Архивная информация',
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
href: DEFAULT_ORIGIN,
|
|
137
|
+
text: 'О банке',
|
|
138
|
+
target: '_blank',
|
|
139
|
+
items: [
|
|
140
|
+
{
|
|
141
|
+
href: DEFAULT_ORIGIN,
|
|
142
|
+
text: 'О банке',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
href: DEFAULT_ORIGIN,
|
|
146
|
+
text: 'Новости',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
href: DEFAULT_ORIGIN,
|
|
150
|
+
text: 'Офисы и отделения',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
href: DEFAULT_ORIGIN,
|
|
154
|
+
text: 'Карьера в банке',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
href: DEFAULT_ORIGIN,
|
|
158
|
+
text: 'Пресс-центр',
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
href: DEFAULT_ORIGIN,
|
|
162
|
+
text: 'Кредитным организациям',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
href: DEFAULT_ORIGIN,
|
|
166
|
+
text: 'Закупки',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
href: DEFAULT_ORIGIN,
|
|
170
|
+
text: 'Непрофильные/Профильные нецелевые активы',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
href: DEFAULT_ORIGIN,
|
|
174
|
+
text: 'Инсайдерам',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
href: DEFAULT_ORIGIN,
|
|
178
|
+
text: 'Противодействие коррупции',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
href: DEFAULT_ORIGIN,
|
|
182
|
+
text: 'Меры безопасности',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
href: DEFAULT_ORIGIN,
|
|
186
|
+
text: 'Залоговое имущество',
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
]}
|
|
191
|
+
socialMedia={[{ href: 'https://vk.com' }, { href: 'https://ok.ru' }, { href: 'https://t.me' }]}
|
|
192
|
+
contacts={[
|
|
193
|
+
{
|
|
194
|
+
text: '+7 (495) 787-7-787',
|
|
195
|
+
description: 'Для звонков из-за границы',
|
|
196
|
+
type: 'tel',
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
text: 'example@example.com',
|
|
200
|
+
description: 'Для писем',
|
|
201
|
+
type: 'email',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
text: '7787',
|
|
205
|
+
description: 'Абонентам МТС, Мегафон, Билайн и Tele2',
|
|
206
|
+
type: 'tel',
|
|
207
|
+
},
|
|
208
|
+
]}
|
|
209
|
+
relatedEnterprises={[
|
|
210
|
+
{
|
|
211
|
+
text: 'РСХБ Страхование',
|
|
212
|
+
href: DEFAULT_ORIGIN,
|
|
213
|
+
target: '_blank',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
text: 'РСХБ Страхование жизни',
|
|
217
|
+
href: DEFAULT_ORIGIN,
|
|
218
|
+
target: '_blank',
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
text: 'РСХБ Управление активами',
|
|
222
|
+
href: DEFAULT_ORIGIN,
|
|
223
|
+
target: '_blank',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
text: 'РСХБ Лизинг',
|
|
227
|
+
href: DEFAULT_ORIGIN,
|
|
228
|
+
target: '_blank',
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
text: 'РСХБ Факторинг',
|
|
232
|
+
href: DEFAULT_ORIGIN,
|
|
233
|
+
target: '_blank',
|
|
234
|
+
},
|
|
235
|
+
]}
|
|
236
|
+
documents={[
|
|
237
|
+
{
|
|
238
|
+
text: 'Информация о процентных ставках по договорам банковского вклада с физическими лицами',
|
|
239
|
+
href: DEFAULT_ORIGIN,
|
|
240
|
+
target: '_blank',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
text: 'Раскрытие информации профессиональным участником рынка ценных бумаг',
|
|
244
|
+
href: DEFAULT_ORIGIN,
|
|
245
|
+
target: '_blank',
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
text: 'Раскрытие информации',
|
|
249
|
+
href: DEFAULT_ORIGIN,
|
|
250
|
+
target: '_blank',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
text: 'Удостоверяющий центр',
|
|
254
|
+
href: DEFAULT_ORIGIN,
|
|
255
|
+
target: '_blank',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
text: 'Финансовая культура',
|
|
259
|
+
href: DEFAULT_ORIGIN,
|
|
260
|
+
target: '_blank',
|
|
261
|
+
},
|
|
262
|
+
]}
|
|
263
|
+
context={context}
|
|
264
|
+
/>
|
|
265
|
+
);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
+
import { Logo } from '../ui-kit/Logo';
|
|
3
|
+
import { SearchBar } from '../ui-kit/SearchBar';
|
|
4
|
+
import { Contacts } from './Contacts';
|
|
5
|
+
import { Sitemap } from './Sitemap';
|
|
6
|
+
import { SocialMedia } from './SocialMedia';
|
|
7
|
+
import { HorizontalNavigation } from './HorizontalNavigation';
|
|
8
|
+
import { TextInformation } from './TextInformation';
|
|
9
|
+
import type { LinkContent, UniBlockProps, ContactInfo, TopMenuItem } from '../types';
|
|
10
|
+
|
|
11
|
+
const LEFT_COL_WIDTH_FULL_HD = 'w-[280px]';
|
|
12
|
+
const LEFT_COL_WIDTH_SMALL_DESKTOP = 'xl:w-[220px]';
|
|
13
|
+
|
|
14
|
+
export interface FooterContent {
|
|
15
|
+
documents?: LinkContent[];
|
|
16
|
+
relatedEnterprises?: LinkContent[];
|
|
17
|
+
contacts?: ContactInfo[];
|
|
18
|
+
socialMedia?: Omit<LinkContent, 'text'>[];
|
|
19
|
+
topItems?: TopMenuItem[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface FooterProps extends FooterContent, UniBlockProps {}
|
|
23
|
+
|
|
24
|
+
export const Footer = JSX<FooterProps>(
|
|
25
|
+
({ className, documents, relatedEnterprises, contacts, socialMedia, topItems, context }) => {
|
|
26
|
+
return (
|
|
27
|
+
<footer className={`${className} px-9 py-2 bg-white rounded-bl-3xl rounded-br-3xl`}>
|
|
28
|
+
<div className="flex items-stretch gap-32 py-8 xl:gap-8">
|
|
29
|
+
<Logo className={`${LEFT_COL_WIDTH_FULL_HD} ${LEFT_COL_WIDTH_SMALL_DESKTOP}`} />
|
|
30
|
+
<SearchBar context={context} className="grow" />
|
|
31
|
+
</div>
|
|
32
|
+
<div className="flex items-stretch gap-32 xl:gap-8">
|
|
33
|
+
<Contacts
|
|
34
|
+
className={`${LEFT_COL_WIDTH_FULL_HD} shrink-0 overflow-hidden ${LEFT_COL_WIDTH_SMALL_DESKTOP}`}
|
|
35
|
+
items={contacts}
|
|
36
|
+
context={context}
|
|
37
|
+
hasButton
|
|
38
|
+
/>
|
|
39
|
+
<Sitemap className="pt-[3px]" context={context} items={topItems} />
|
|
40
|
+
</div>
|
|
41
|
+
<SocialMedia media={socialMedia} context={context} />
|
|
42
|
+
<HorizontalNavigation links={relatedEnterprises} context={context} />
|
|
43
|
+
<TextInformation links={documents} context={context} />
|
|
44
|
+
</footer>
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
+
import type { FooterLink } from './FooterLink';
|
|
3
|
+
import { useLink } from '../useLink';
|
|
4
|
+
import { LinkContent } from '../types';
|
|
5
|
+
|
|
6
|
+
export const HorizontalNavigation = JSX<FooterLink>(({ className, links, context }) => {
|
|
7
|
+
const router = context.useRouter();
|
|
8
|
+
const { handlerDecorator } = context;
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div className={`${className || ''}`}>
|
|
12
|
+
{links?.length ? (
|
|
13
|
+
<div className="flex justify-between items-center gap-5 py-5 border-solid border-x-0 border-y-1 border-y-main-divider">
|
|
14
|
+
{links.map((_, i) => (
|
|
15
|
+
<HorizontalNavigationLink
|
|
16
|
+
key={String(i)}
|
|
17
|
+
index={i}
|
|
18
|
+
{...useLink({ router, handlerDecorator }, _)}
|
|
19
|
+
/>
|
|
20
|
+
))}
|
|
21
|
+
</div>
|
|
22
|
+
) : null}
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
interface HorizontalNavigationLinkProps extends LinkContent {
|
|
28
|
+
className: string;
|
|
29
|
+
index: number;
|
|
30
|
+
onClick: (ev: MouseEvent) => any;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const HorizontalNavigationLink = JSX<Partial<HorizontalNavigationLinkProps>>(
|
|
34
|
+
({ className, index, text, href, target, onClick }) => (
|
|
35
|
+
<a
|
|
36
|
+
className={`font-sans font-normal text-sm text-secondary-text hover:text-primary-text inline-block no-underline max-w-[292px] ${
|
|
37
|
+
className || ''
|
|
38
|
+
}`}
|
|
39
|
+
href={href}
|
|
40
|
+
target={target}
|
|
41
|
+
onClick={onClick}
|
|
42
|
+
>
|
|
43
|
+
{text || `Документ ${index}`}
|
|
44
|
+
</a>
|
|
45
|
+
),
|
|
46
|
+
);
|