Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions src/homeworks/ts1/3_write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
* Поэтому в идеале чтобы функции возвращали случайные данные, но в то же время не абракадабру.
* В целом сделайте так, как вам будет удобно.
* */
import crypto from 'crypto';
import { names, photos, nouns, adjectives } from './data';
import { names, photos, nouns, adjectives, bankCategories, bankOperations } from './data';

type Category = {
id: string;
Expand All @@ -24,7 +23,7 @@ type Product = {
category: Category;
};

type Operation = Cost | Profit;
export type Operation = Cost | Profit;

type Cost = {
id: string;
Expand All @@ -49,30 +48,30 @@ type Profit = {
const getRandomItemFromArray = <T>(arr: T[]): T => arr[Math.floor(Math.random() * arr.length)];
const getRandomNumber = (min: number, max: number): number => Math.floor(Math.random() * (max - min + 1)) + min;
const getRandomDescription = (nouns: string[], adjectives: string[]): string => {
const fourAdjectives = [...Array(4)].map(() => getRandomItemFromArray(adjectives)).join(' ');
const someAdjectives = [...Array(50)].map(() => getRandomItemFromArray(adjectives)).join(' ');
const noun = getRandomItemFromArray(nouns);
return `${fourAdjectives} ${noun}`;
return `${someAdjectives} ${noun}`;
};
const getRandomId = crypto.randomUUID;
const getRandomId = () => `${getRandomNumber(1000, 9999)}-${getRandomNumber(1000, 9999)}`;
const createRandomCategory = (): Category => ({
id: getRandomId(),
name: getRandomItemFromArray(names),
name: getRandomItemFromArray(bankCategories),
photo: getRandomItemFromArray(photos),
});

const createRandomCost = (createdAt: string): Cost => ({
id: getRandomId(),
name: getRandomItemFromArray(names),
name: getRandomItemFromArray(bankOperations),
desc: getRandomDescription(nouns, adjectives),
createdAt,
amount: getRandomNumber(100, 1000),
amount: getRandomNumber(-100, -1000),
category: createRandomCategory(),
type: 'Cost',
});

const createRandomProfit = (createdAt: string): Profit => ({
id: getRandomId(),
name: getRandomItemFromArray(names),
name: getRandomItemFromArray(bankOperations),
desc: getRandomDescription(nouns, adjectives),
createdAt,
amount: getRandomNumber(100, 1000),
Expand Down
122 changes: 122 additions & 0 deletions src/homeworks/ts1/data.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,125 @@
export const bankCategories = [
'Account Management',
'Transactions',
'Loan Services',
'Credit Card Services',
'Investment Services',
'Online and Mobile Banking',
'Customer Support',
'Foreign Exchange Services',
'Other Services',
'Security Services',
'Digital Banking',
'Insurance Services',
'Financial Planning',
'Mortgage Services',
'Business Banking Services',
'ATM Services',
];

export const bankOperations = [
'Open Savings Account',
'Close Savings Account',
'Open Checking Account',
'Close Checking Account',
'Open Fixed Deposit Account',
'Close Fixed Deposit Account',
'Open Joint Account',
'Close Joint Account',
'Update Account Information',
'Change Account Type',
'Deposit Cash',
'Withdraw Cash',
'Transfer Funds',
'Receive Funds',
'Pay Bills',
'Online Payment',
'Recurring Payments',
'Stop Payment Request',
'Issue Checks',
'Cancel Checks',
'Apply for Personal Loan',
'Apply for Home Loan',
'Apply for Auto Loan',
'Apply for Student Loan',
'Pay Loan Installment',
'Pay Loan Off Early',
'Refinance Loan',
'Loan Balance Inquiry',
'Loan Statement Request',
'Loan Insurance',
'Apply for Credit Card',
'Activate Credit Card',
'Block Credit Card',
'Unblock Credit Card',
'Increase Credit Limit',
'Decrease Credit Limit',
'Pay Credit Card Bill',
'Credit Card Balance Inquiry',
'Report Lost Credit Card',
'Credit Card Statement Request',
'Open Investment Account',
'Close Investment Account',
'Buy Stocks',
'Sell Stocks',
'Buy Bonds',
'Sell Bonds',
'Mutual Fund Investment',
'Withdraw Investment',
'Investment Account Statement',
'Investment Advisory Services',
'Register for Online Banking',
'Login to Online Banking',
'Reset Online Banking Password',
'Mobile Banking Registration',
'Mobile Banking App Download',
'Mobile Check Deposit',
'Online Fund Transfer',
'View Account Statements',
'Set Up Alerts',
'Online Bill Payment',
'Account Inquiry',
'Transaction Dispute',
'Account Lock/Unlock',
'Complaint Registration',
'General Banking Information',
'ATM Card Issues',
'Branch Locator',
'Update Contact Details',
'Request for Document Copies',
'Fraud Alert Reporting',
'Currency Exchange',
'Foreign Currency Account Opening',
'International Fund Transfer',
'International Check Deposit',
'Foreign Currency Loan',
'Forex Card Application',
'Forex Card Reload',
'Forex Card Balance Inquiry',
'Currency Rate Inquiry',
'Foreign Draft Issue',
'Safe Deposit Box Rental',
'Safe Deposit Box Access',
'Notary Services',
'Document Certification',
'Tax Payment Services',
'Utility Bill Payments',
'Property Valuation Services',
'Mortgage Services',
'Wealth Management Services',
'Retirement Planning Services',
'Activate Two-Factor Authentication',
'Deactivate Two-Factor Authentication',
'Change PIN/Password',
'Set Up Security Questions',
'Biometric Authentication Setup',
'Review Security Settings',
'Security Alerts & Notifications',
'Anti-Money Laundering Reports',
'Suspicious Activity Monitoring',
'Data Privacy Requests',
];

export const names = [
'Emma',
'Liam',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.operation-dynamic-list {
display: flex;
flex-direction: column;
gap: 15px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { useCallback, useRef, useState } from 'react';
import { OperationList } from '../operation-list/OperationList';
import { createRandomOperation, Operation } from '../../../homeworks/ts1/3_write';
import s from './OperationDynamicList.module.scss';

const createOpearation = () => createRandomOperation(new Date().toLocaleDateString());
const createBatchOperations = (nr: number) => Array.from(Array(nr), () => createOpearation());

export const OperationDynamicList = () => {
const [operations, setOperations] = useState<Operation[]>(createBatchOperations(5));
const addMoreOperations = () => setOperations((prev) => [...prev, ...createBatchOperations(5)]);
const observer = useRef<IntersectionObserver | null>(null);

const lastOperationRef = useCallback((node: HTMLDivElement) => {
observer.current && observer.current.disconnect();
observer.current = new IntersectionObserver((items) => items[0].isIntersecting && addMoreOperations());
node && observer.current.observe(node);
}, []);

return (
<div className={s['operation-dynamic-list']}>
<OperationList items={operations} />
<div ref={lastOperationRef}></div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.container {
display: flex;
flex-direction: column;
gap: 20px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { useState } from 'react';
import { OperationList } from '../operation-list/OperationList';
import { Button } from '../../button/Button';
import { createRandomOperation, Operation } from '../../../homeworks/ts1/3_write';
import s from './OperationListAddMore.module.scss';

const createOpearation = () => createRandomOperation(new Date().toLocaleDateString());
const createBatchOperations = (nr: number) => Array.from(Array(nr), () => createOpearation());

export const OperationListAddMore = () => {
const [operations, setOperations] = useState<Operation[]>(createBatchOperations(2));
const addMoreOperations = () => setOperations((prev) => [...prev, ...createBatchOperations(2)]);

return (
<div className={s.container}>
<OperationList items={operations} />
<Button onClick={addMoreOperations}>Показать еще</Button>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.operation-list {
display: flex;
flex-direction: column;
gap: 15px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { OperationDetail } from '../operation-detail/OperationDetail';
import { Operation as OperationProps } from '../../../homeworks/ts1/3_write';
import s from './OperationList.module.scss';

type OperationItemProps = Omit<OperationProps, 'id'>;

const OperationItem = (data: OperationItemProps) => (
<OperationDetail
amount={data.amount}
category={data.category.name}
date={data.createdAt}
description={data.desc}
title={data.name}
/>
);

type OperationListProps = {
items: OperationProps[];
};

export const OperationList = ({ items }: OperationListProps) => (
<div className={s['operation-list']}>
{items.map((item) => {
const { id, ...rest } = item;
return <OperationItem {...rest} key={id} />;
})}
</div>
);
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@
font-weight: bold;
margin-top: 10px;
}

.cost {
color: crimson;
}
3 changes: 2 additions & 1 deletion src/shared/icome-expenses-accounting/operation/Operation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import cn from 'clsx';
import s from './Operation.module.scss';

export type OperationProps = {
Expand All @@ -9,7 +10,7 @@ export type OperationProps = {

export const Operation = (data: OperationProps) => (
<>
<div className={s.amount}>{data.amount}</div>
<div className={cn(s.amount, data.amount < 0 && s.cost)}>{data.amount}</div>
<div className={s.category}>{data.category}</div>
<div className={s.title}>{data.title}</div>
</>
Expand Down
8 changes: 6 additions & 2 deletions src/shared/modal-form/ModalForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ type ModalFormProps = {
onClose?: (event: MouseEvent<HTMLButtonElement>) => void;
};

export const ModalForm = ({ visible = true, onClose, children }: ModalFormProps) =>
!!visible && (
export const ModalForm = ({ visible = true, onClose, children }: ModalFormProps) => {
if (!visible) {
return null;
}

return (
<div className={s.modal}>
<div className={s['modal-content']}>
<span className={s.close} onClick={onClose}>
Expand Down
10 changes: 10 additions & 0 deletions src/shared/portal-modal-form/PortalModalForm.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.portal-modal {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;

input {
align-self: stretch;
}
}
28 changes: 28 additions & 0 deletions src/shared/portal-modal-form/PortalModalForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, { useState, FormEvent } from 'react';
import { createPortal } from 'react-dom';
import { Button } from '../button/Button';
import { TextInput } from '../text-input/TextInput';
import { ModalForm } from '../modal-form/ModalForm';
import s from './PortalModalForm.module.scss';

export const PortalModalForm = () => {
const [inputValue, setInputValue] = useState('');
const [isModalFormVisible, setIsModalFormVisible] = useState(false);

const openModalForm = () => setIsModalFormVisible(true);
const closeModalForm = () => setIsModalFormVisible(false);
const saveInputValue = (event: FormEvent<HTMLInputElement>) => setInputValue(event.currentTarget.value);

return (
<div className={s['portal-modal']}>
<TextInput value={inputValue} onInput={saveInputValue} />
<Button onClick={openModalForm}>Открыть модальное окно</Button>
{createPortal(
<ModalForm visible={isModalFormVisible} onClose={closeModalForm}>
<p>{inputValue}</p>
</ModalForm>,
document.body
)}
</div>
);
};
2 changes: 1 addition & 1 deletion src/stories/InputToModal.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { StatefullModalForm } from '../shared/statefull-modal-form/StatefullModa

const meta: Meta<typeof StatefullModalForm> = {
component: StatefullModalForm,
title: 'Общее задание/Состояние модального окна',
title: 'Общее задание/Модальное окно/С состоянием',
tags: ['autodocs'],
parameters: {
docs: {
Expand Down
13 changes: 13 additions & 0 deletions src/stories/InputToPortalModal.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Meta } from '@storybook/react';

import { PortalModalForm } from '../shared/portal-modal-form/PortalModalForm';

const meta: Meta<typeof PortalModalForm> = {
component: PortalModalForm,
title: 'Общее задание/Модальное окно/С порталом',
tags: ['autodocs'],
};

export default meta;

export const Test = {};
2 changes: 1 addition & 1 deletion src/stories/ModalForm.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const SomeContent = () => (

const meta: Meta<typeof ModalForm> = {
component: ModalForm,
title: 'Общее задание/Модальное окно',
title: 'Общее задание/Модальное окно/Модальное окно',
tags: ['autodocs'],
argTypes: {
children: {
Expand Down
Loading