Added the sample into the repository.

This commit is contained in:
RagunathSukumaran 2022-09-30 16:13:02 +05:30
Родитель bd7878953b
Коммит dff19006a3
19 изменённых файлов: 27709 добавлений и 0 удалений

7
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,7 @@
.npmrc
.vscode/
node_modules/
src/**/*.js
dist/
styles/*.*
!styles/index.css

9
.npmignore Normal file
Просмотреть файл

@ -0,0 +1,9 @@
.npmrc
.vscode/
.npmignore
config.json
gulpfile.js
tsconfig.json
node-modules/
Jenkinsfile
src/**/*.js

28
Jenkinsfile поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
#!groovy
node('EJ2Component') {
try {
deleteDir()
stage('Import') {
git url: 'https://github.com/essential-studio/ej2-groovy-scripts.git', branch: 'master', credentialsId: env.GithubCredentialID
shared = load 'src/shared.groovy'
}
stage('Checkout') {
checkout scm
shared.getProjectDetails()
shared.gitlabCommitStatus('running')
}
stage('Install') {
shared.install()
}
deleteDir()
}
catch(Exception e) {
shared.throwError(e)
deleteDir()
}
}

9
config.json Normal file
Просмотреть файл

@ -0,0 +1,9 @@
{
"styleDependency": [
"ej2"
],
"isShowCase": true,
"publishSamples": [
"./build/**"
]
}

1
gulpfile.js Normal file
Просмотреть файл

@ -0,0 +1 @@
require("@syncfusion/ej2-build");

10
license Normal file
Просмотреть файл

@ -0,0 +1,10 @@
Essential JS 2 library is available under the Syncfusion Essential Studio program, and can be licensed either under the Syncfusion Community License Program or the Syncfusion commercial license.
To be qualified for the Syncfusion Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusions terms and conditions.
Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options.
Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusions license containing all terms and conditions.
The Syncfusion license that contains the terms and conditions can be found at
https://www.syncfusion.com/content/downloads/syncfusion_license.pdf

56
package.json Normal file
Просмотреть файл

@ -0,0 +1,56 @@
{
"name": "@syncfusion/ej2-react-samples-template",
"version": "0.0.1",
"description": "Essential JS 2 for React - Samples template",
"author": "Syncfusion Inc.",
"license": "SEE LICENSE IN license",
"dependencies": {
"@syncfusion/ej2-react-buttons": "*",
"@syncfusion/ej2-react-calendars": "*",
"@syncfusion/ej2-react-charts": "*",
"@syncfusion/ej2-react-grids": "*",
"@syncfusion/ej2-react-inputs": "*",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
"typescript": "^4.6.4",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@syncfusion/ej2-build": "*",
"@types/jest": "^27.5.1",
"@types/node": "^16.11.36",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.4",
"style-loader": "^0.23.1",
"typescript": "^3.1.6"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"ci-publish": "gulp publish-samples"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Двоичные данные
public/favicon.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.4 KiB

27
public/index.html Normal file
Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Essential JS 2 for React - Loan Calculator - You can use this application to Calculates your loan payment based on your loan amount, interest and term"
/>
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Essential JS 2 for React - Loan Calculator</title>
<link rel="icon" type="image/x-icon" href="../src/favicon.ico">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Raleway:500,600" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reflect-metadata/0.1.10/Reflect.min.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

15
public/manifest.json Normal file
Просмотреть файл

@ -0,0 +1,15 @@
{
"short_name": "Syncfusion Loan Calculator",
"name": "Essential JS 2 for React - Loan Calculator",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

813
src/App.tsx Normal file
Просмотреть файл

@ -0,0 +1,813 @@
import { DetailRow, GridComponent, GridModel, Inject, Page } from '@syncfusion/ej2-react-grids';
import { ChangeEventArgs, SliderComponent, SliderTickRenderedEventArgs } from '@syncfusion/ej2-react-inputs';
import { NumericTextBoxComponent } from '@syncfusion/ej2-react-inputs';
import { RadioButtonComponent } from '@syncfusion/ej2-react-buttons';
import { DatePickerComponent } from '@syncfusion/ej2-react-calendars';
import { AccumulationChartComponent, AccumulationSeriesCollectionDirective, AccumulationSeriesDirective, AxesDirective, AxisDirective, IAccPointRenderEventArgs, IAxisLabelRenderEventArgs, PieSeries, StackingColumnSeries } from '@syncfusion/ej2-react-charts';
import { ChartComponent, Legend, LineSeries, SeriesCollectionDirective, SeriesDirective } from '@syncfusion/ej2-react-charts';
import { DateTime, Tooltip } from '@syncfusion/ej2-react-charts';
import { closest, Internationalization } from '@syncfusion/ej2-base';
import { isNullOrUndefined as isNOU } from '@syncfusion/ej2-base';
import './index.css';
import './styles.css';
import { useEffect, useRef, useState } from 'react';
export default function App() {
const [loanTicks, setLoanTicks] = useState({});
const [dateValue, setDateValue] = useState(new Date());
const [interestValue, setInterestValue] = useState(5.5);
const [yearTenure, setYearTenure] = useState(true);
let emiAmt: string = '';
let principalAmt: string = '';
let interestAmt: string = '';
let totalAmt: string = '';
const [principalValue, setPrincipalValue] = useState(300000);
const [loanValue, setLoanValue] = useState(15);
let grid = useRef(null);
let accChart = useRef(null);
let acc1 = useRef(null);
let principalNumRef = useRef(null);
let principalSliderRef = useRef(null);
let interestSliderRef = useRef(null);
let interestNumRef = useRef(null);
let loanSliderRef = useRef(null);
let loanNumRef = useRef(null);
let pie = useRef(null);
let emi: number = 0;
let tempPrincipalValue: number = 0;
let beginBalance: number = 30000;
let tent: number = 0;
let totalPrincipalYear: number = 0;
let totalInterestYear: number = 0;
let tempInterest: number = 0;
let dataUnits: Array<Object> = [];
let yearWiseData: Array<Object> = [];
let dateObj: Date = new Date();
let totalInterest: number = 0;
let totalAmount: number = 0;
let totalPrincipal: number = 0;
let endBalance: number = 0;
let yearTotal: number = 0;
let child: GridModel;
let interestNumFormat: string = '#.##\' %\'';
let loanNumFormat: string = '#.##';
let monthNames: Array<string> = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'];
let intl: Internationalization = new Internationalization();
let legendSettings: Object = {
textStyle: {
color: '#FFFFFF',
fontFamily: 'Raleway, sans-serif',
fontWeight: '600',
opacity: 0.62,
size: '16px',
}
};
let format: string = 'c0';
let principalTicks: Object = { placement: 'After', largeStep: 100000, smallStep: 10000, showSmallTicks: false, format: 'c0' };
const [interestTicks, setInterestTicks] = useState({});
let labelStyle: any;
let titleStyle: any;
let columns: any;
const [loanNumMinValue, setLoanNumMinValue] = useState(1);
const [loanNumMaxValue, setLoanNumMaxValue] = useState(40);
const [loanMaxValue, setLoanMaxValue] = useState(40);
const [loanNumStep, setLoanNumStep] = useState(1);
const [loanStep, setLoanStep] = useState(1);
const [loanMinValue, setLoanMinValue] = useState(0);
let princAmount = useRef(null);
let totalInt = useRef(null);
let totalPay = useRef(null);
let monPayment = useRef(null);
let monthChange = useRef(null);
let yearChange = useRef(null);
const [paymentHideAtMedia, setPaymentHideAtMedia] = useState('(min-width: 480px)');
function setInitValues(): void {
emi = calculateEMI();
tempPrincipalValue = principalValue;
tent = yearTenure ? (loanValue * 12) : loanValue;
dataUnits = [];
yearWiseData = [];
dateObj = new Date(dateValue.getTime());
totalInterest = 0;
totalAmount = 0;
totalPrincipal = 0;
totalPrincipalYear = 0;
totalInterestYear = 0;
emiAmt = getCurrencyVal(tent ? Math.round(emi) : 0);
interestAmt = getCurrencyVal(tent ? Math.round((emi * tent) - tempPrincipalValue) : 0);
totalAmt = getCurrencyVal(tent ? Math.round((emi * tent)) : 0);
principalAmt = getCurrencyVal(tempPrincipalValue);
}
function calculateEMI(): number {
let interestValue: number = getInterest();
let tent: number = yearTenure ? (loanValue * 12) : loanValue;
if (interestValue) {
return principalValue * interestValue *
(Math.pow((1 + interestValue), tent)) / ((Math.pow((1 + interestValue), tent)) - 1);
}
return principalValue / tent;
}
function getInterest(): number {
return interestValue ? parseFloat('' + interestValue / 12 / 100) : 0;
}
function getCurrencyVal(value: number): string {
return intl.formatNumber(value, { format: 'C0' });
}
function principalRenderedTicks(args: SliderTickRenderedEventArgs): void {
let li: HTMLCollectionBase = args.ticksWrapper.getElementsByClassName('e-large');
for (let i: number = 0; i < li.length; ++i) {
let ele: HTMLElement = (li[i].querySelectorAll('.e-tick-value')[0] as HTMLElement);
let num: number = parseInt(ele.innerText.substring(1).replace(/,/g, ''), 10) / 1000;
ele.innerText = num === 0 ? ('' + num) : (num + 'K');
}
}
const principalNumChange = (args: any): void => {
(principalSliderRef.current as any).value = args.value
setPrincipalValue(args.value);
}
const principalChanged = (args: any): void => {
(principalNumRef.current as any).value = args.value
setPrincipalValue(args.value);
}
const interestNumChange = (args: any): void => {
(interestSliderRef.current as any) = args.value
setInterestValue(args.value);
}
const interestChanged = (args: any): void => {
(interestNumRef.current as any).value = args.value
setInterestValue(args.value);
}
const loanNumChange = (args: any): void => {
(loanSliderRef.current as any).value = args.value;
setLoanValue(args.value);
}
const loanChanged = (args: any): void => {
(loanNumRef.current as any).value = args.value;
setLoanValue(args.value);
}
const updateDateValue = (args: any): void => {
dateObj = args.value
if (isNOU(args.value)) {
setDateValue(new Date());
} else {
setDateValue(args.value);
}
}
function monthChanged(args: ChangeEventArgs): void {
setYearTenure(false);
setLoanNumMinValue(12);
setLoanNumMaxValue(480);
setLoanNumStep(12);
setLoanMaxValue(480);
setLoanValue(loanValue * 12);
setLoanStep(12);
setLoanTicks({ placement: 'After', largeStep: 120, smallStep: 12, showSmallTicks: false });
}
function yearChanged(args: ChangeEventArgs): void {
setYearTenure(true);
setLoanNumMinValue(1);
setLoanNumMaxValue(40);
setLoanNumStep(1);
setLoanMaxValue(40);
setLoanValue(loanValue / 12);
setLoanStep(1);
setLoanTicks({ placement: 'After', largeStep: 10, smallStep: 1, showSmallTicks: false });
}
function axisLabelRender(args: IAxisLabelRenderEventArgs): void {
if (window.innerWidth < 576) {
if (args.axis.name === 'primaryYAxis' || args.axis.name === 'yAxis1') {
let value: number = Number(args.value) / 1000;
args.text = value === 0 ? String(value) : (String(value) + 'K');
}
}
}
function calRangeValues(): void {
for (let i: number = 0; i < tent; i++) {
tempInterest = getInterest() ? (tempPrincipalValue * getInterest()) : tempPrincipalValue;
totalInterest += tempInterest;
totalAmount += emi;
totalPrincipal += parseFloat((emi - tempInterest).toFixed(2));
endBalance = tempPrincipalValue - (emi - tempInterest);
yearTotal += emi;
totalPrincipalYear += parseFloat((emi - tempInterest).toFixed(2));
totalInterestYear += tempInterest;
dataUnits.push({
month: monthNames[dateObj.getMonth()],
index: (i + 1),
totalInterest: Math.round(totalInterest),
totalAmount: totalAmount,
emi: Math.round(emi),
year: dateObj.getFullYear(),
beginningBalance: Math.round(tempPrincipalValue),
interest: Math.round(tempInterest),
principalPaid: Math.round((emi - tempInterest)),
endingBalance: Math.round(endBalance)
});
if (i === 0 || dateObj.getMonth() === 0) {
beginBalance = tempPrincipalValue;
}
if (dateObj.getMonth() === 11 || (i === tent - 1)) {
yearWiseData.push({
beginningBalance: Math.round(beginBalance),
totalInterest: Math.round(totalInterest),
totalPrincipal: Math.round(totalPrincipal),
totalAmount: Math.round(totalAmount),
yearTotal: Math.round(yearTotal),
endingBalance: Math.round(endBalance),
yearN: new Date(dateObj.getFullYear(), 0, 1),
year: dateObj.getFullYear(),
yearPrincipal: totalPrincipalYear,
yearInterest: totalInterestYear
});
yearTotal = 0;
totalPrincipalYear = 0;
totalInterestYear = 0;
}
tempPrincipalValue = endBalance;
if (i < tent - 1) {
dateObj.setMonth(dateObj.getMonth() + 1);
}
}
}
function gridTemplate(props: any): any {
return (
<div>
<div className="e-icons e-icon-grightarrow e-row-toggle"></div>
<span id="abc">{props.year}</span>
</div>
);
}
function onclickEvent(args: any) {
debugger;
let target: any = args.target as Element;
if (target.classList.contains('e-row-toggle') || target.parentElement.querySelector('.e-row-toggle')) {
target = target.parentElement.querySelector('.e-row-toggle') ? target.parentElement.querySelector('.e-row-toggle') : target;
if (target.classList.contains('e-icon-gdownarrow')) {
target.classList.remove('e-icon-gdownarrow');
target.classList.add('e-icon-grightarrow');
(grid.current as any).detailRowModule.collapse(parseInt((closest(target, 'tr') as HTMLElement).getAttribute('data-rowindex')!, 10));
} else {
target.classList.remove('e-icon-grightarrow');
target.classList.add('e-icon-gdownarrow');
(grid.current as any).detailRowModule.expand(parseInt((closest(target, 'tr') as HTMLElement).getAttribute('data-rowindex')!, 10));
}
}
gridHide();
}
function pointRender(args: IAccPointRenderEventArgs): void {
if (args.point.index) {
args.border.width = 7;
args.fill = 'url(#interest_svg)';
} else {
args.border.width = 7;
args.border.color = '#162036';
args.fill = 'url(#principal_svg)';
}
}
columns = [
{
headerText:'Year',
template: gridTemplate,
minWidth: '80px',
textAlign:'Center',
},
{
field:'yearTotal',
headerText:'Payment',
minWidth:'80px',
format:format,
textAlign:'Center',
hideAtMedia:paymentHideAtMedia,
},
{
field:'yearPrincipal',
headerText:'Principal Paid',
minWidth:'80px',
format:format,
textAlign:'Center',
},
{
field:'yearInterest',
headerText:'Interest Paid',
minWidth:'80px',
format:format,
textAlign:'Center',
},
{
field:'endingBalance',
headerText:'Balance',
minWidth:'80px',
format:format,
textAlign:'Center',
}
]
function gridHide() {
if (width < 439) {
let grid: any = document.getElementsByClassName('e-grid');
for (let i=0; i < grid.length; i++){
grid[i].ej2_instances[0].hideColumns('Payment');
}
}
}
setInitValues();
calRangeValues();
child = {
queryString: 'year',
cssClass: "child-grid-custom",
columns: [
{ field: 'month', headerText: 'Month', textAlign: 'Center', minWidth: '80px' },
{ field: 'emi', headerText: 'Payment', textAlign: 'Center', format: 'C0', minWidth: '80px' },
{ field: 'principalPaid', headerText: 'Principal Paid', textAlign: 'Center', format: 'C0', minWidth: '80px' },
{ field: 'interest', headerText: 'Interest Paid', textAlign: 'Center', format: 'C0', minWidth: '80px' },
{ field: 'endingBalance', headerText: 'Balance', textAlign: 'Center', format: 'C0', minWidth: '80px' }
],
dataSource: dataUnits
};
labelStyle = {
color: '#989CA9',
fontFamily: 'Roboto',
fontWeight: '400',
size: '16px',
};
titleStyle = {
color: '#FFFFFF',
fontFamily: 'Raleway, sans-serif',
fontWeight: '600',
opacity: 0.62,
size: '16px',
}
let width = window.innerWidth;
if (width <= 350) {
labelStyle = {
color: '#989CA9',
fontFamily: 'Roboto',
fontWeight: '400',
size: '12px',
}
titleStyle = {
color: '#FFFFFF',
fontFamily: 'Raleway, sans-serif',
fontWeight: '600',
opacity: 0.62,
size: '12px',
}
}
useEffect(() => {
setLoanTicks({
placement: 'After',
largeStep: 10,
smallStep: 1,
showSmallTicks: false
});
setInterestTicks({ placement: 'After', largeStep: 5, smallStep: 1, showSmallTicks: false });
},[]);
useEffect(() => {
setTimeout(() => {
gridHide();
}, 100);
});
return (
<div>
<h1 className="header-style">Loan Calculator</h1>
<div className="container main-content" id="content">
<div className="row left-content-wrap">
<div className="row loan-content" >
<div className="left-content col-lg-12">
<div className="row form-space" >
<div className="col-lg-12">
<div className="content-space">
<table>
<tbody>
<tr>
<td>
<label className="principal">Loan Amount</label>
</td>
<td>
<div className="editor-space">
<NumericTextBoxComponent
id="principal_txt"
format='c0'
min={1000}
max={5000000}
value={principalValue}
step={10000}
width='200px'
change={principalNumChange}
ref={principalNumRef}
/>
</div>
</td>
</tr>
</tbody>
</table>
</div >
<SliderComponent
id='principal'
min={0}
max={500000}
step={10000}
value={principalValue}
type='MinRange'
ticks={principalTicks}
renderedTicks={principalRenderedTicks}
ref={principalSliderRef}
change={principalChanged}
/>
</div>
</div>
<div className="row form-space">
<div className="col-lg-12">
<div className="content-space">
<table>
<tbody>
<tr>
<td>
<label className="interestrate">Interest Rate</label>
</td>
<td>
<div className="editor-space">
<NumericTextBoxComponent
id="interest_txt"
format={interestNumFormat}
min={0}
max={20}
value={interestValue}
step={.25}
width='165px'
change={interestNumChange}
ref={interestNumRef}
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<SliderComponent
id='interestrate'
min={0}
max={20}
step={.25}
value={interestValue}
type='MinRange'
ticks={interestTicks}
change={interestChanged}
ref={interestSliderRef}
/>
</div>
</div>
</div>
<div className="row form-space">
<div className="col-lg-12">
<div className="content-space">
<table>
<tbody>
<tr>
<td>
<label className="loantenure">Loan Term</label>
<ul className="tenure-value"
>
<li>
<RadioButtonComponent
id="radio1"
label='Month'
name='tenure'
value="month"
change={monthChanged}
ref={monthChange}
/>
</li>
<li>
<RadioButtonComponent
id="radio2"
checked={true}
label='Year'
name='tenure'
value="year"
change={yearChanged}
ref={yearChange}
/>
</li>
</ul>
</td>
<td>
<div className="editor-space">
<NumericTextBoxComponent
id="loan_txt"
format={loanNumFormat}
min={loanNumMinValue}
max={loanNumMaxValue}
value={loanValue}
step={loanNumStep}
width='150px'
change={loanNumChange}
ref={loanNumRef}
/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div id='loantenure'>
<SliderComponent
id='loantenure'
min={loanMinValue}
max={loanMaxValue}
step={loanStep}
value={loanValue}
type='MinRange'
ticks={loanTicks}
change={loanChanged}
ref={loanSliderRef}
/>
</div>
</div>
</div>
</div>
</div>
<div className="row loan-content">
<div className="col-lg-12 emi-content">
<div>
<h6 className="emi-header">Break-up of Total Payment</h6>
</div>
<div className="row">
<div className="col-lg-7">
<AccumulationChartComponent
dataSource={[
{
'x': 'Principal Amount',
y: principalValue
},
{
'x': 'Interest Amount',
y: ((emi * tent) - principalValue)
}
]}
background='transparent'
id="payment_pieChart"
enableSmartLabels={true}
height="365px"
width='100%'
enableAnimation={true}
legendSettings={{ visible: false }}
tooltip={{ enable: false }}
pointRender={pointRender}
ref={pie}
>
<Inject services={[PieSeries, Legend, Tooltip]} />
<AccumulationSeriesCollectionDirective>
<AccumulationSeriesDirective
xName='x'
yName='y'
type='Pie'
radius='80%'
startAngle={290}
endAngle={290}
innerRadius='60%'
explode={true}
explodeOffset='10%'
explodeIndex={3}
>
</AccumulationSeriesDirective>
</AccumulationSeriesCollectionDirective>
</AccumulationChartComponent>
</div>
<div className="col-lg-5 pie-content" id="pieContent">
<div>
<p><span className="pie-icon pie-principal"></span>Principal Amount</p>
<h5 id="loan_principal" ref={princAmount} >{principalAmt}</h5>
</div>
<div>
<p><span className="pie-icon pie-interest"></span>Total Interest</p>
<h5 id="loan_interest" ref={totalInt}>{interestAmt}</h5>
</div>
<div className="pie-total">
<span>
<p>Total Payment</p>
<p>(Principal + Interest)</p>
</span>
<h5 id="loan_total_payment" ref={totalPay}>{totalAmt}</h5>
</div>
</div>
</div>
<div>
<h6 className="emi-footer">Your Monthly Payment</h6>
<h1 id="loan_emi" ref={monPayment}>{emiAmt}</h1>
</div>
</div>
<svg height='0px'>
<defs>
<linearGradient id="principal_svg" x1="0" x2="0" y1="0" y2="1">
<stop offset="0"></stop>
<stop offset="1"></stop>
</linearGradient>
<linearGradient id="interest_svg" x1="0" x2="0" y1="0" y2="1">
<stop offset="0"></stop>
<stop offset="1"></stop>
</linearGradient>
</defs>
</svg>
</div>
</div>
<div className="row top-space loan-content"
style={{ textAlign: 'center' }}>
<div className="graph-text">Monthly payments starting from</div>
<div className="graph-input">
< DatePickerComponent
id="monthStarter"
placeholder="Enter date"
start="Year"
showClearButton={false}
showTodayButton={false}
strictMode={true}
depth="Year"
format='MMM yyy'
width='250px'
value={dateValue}
onChange={updateDateValue}
/>
</div>
</div>
<div className="row top-space loan-content max-content">
<h6 className="center-heading">Amortization Chart</h6>
<div className="col-lg-12 graph-container">
<ChartComponent
style={{
textAlign: 'center', display: 'block'
}}
id="paymentGraph"
primaryXAxis={{
title: 'Years',
valueType: 'DateTime',
labelFormat: 'y',
intervalType: 'Years',
majorGridLines: { width: 0 },
minorGridLines: { width: 0 },
majorTickLines: { width: 0 },
minorTickLines: { width: 0 },
lineStyle: { width: 1, dashArray: '2', color: 'rgba(255,255,255,0.2)' },
labelStyle: labelStyle,
titleStyle: titleStyle
}}
primaryYAxis={{
title: 'Balance',
interval: 50000,
minimum: 0,
labelFormat: 'c0',
rangePadding: 'None',
lineStyle: { width: 0 },
majorTickLines: { width: 0 },
majorGridLines: { width: 1, dashArray: '2', color: 'rgba(255,255,255,0.2)' },
minorGridLines: { width: 0 },
minorTickLines: { width: 0 },
labelStyle: labelStyle,
titleStyle: titleStyle
}}
axisLabelRender={axisLabelRender}
tooltip={{
enable: true,
shared: true,
format: '${series.name} : ${point.y}',
header: '<b>${point.x}<b>',
fill: '#FFFFFF',
opacity: 1,
textStyle: {
color: '#555555',
fontFamily: 'Roboto',
size: '12px',
fontWeight: '400',
},
}}
chartArea={{ border: { width: 0 } }}
enableSideBySidePlacement={false}
height="500px"
useGroupingSeparator={true}
background="#27304c"
palettes={['#FB6589', '#3AC8DC', '#FFFFFF']}
titleStyle={{
color: 'White',
fontFamily: 'Raleway, sans-serif',
fontWeight: '500',
size: '20px',
}}
legendSettings={legendSettings}
ref={accChart}
dataSource={yearWiseData}
>
<Inject services={[LineSeries, StackingColumnSeries, DateTime, Legend, Tooltip]} />
<AxesDirective>
<AxisDirective majorGridLines={{ width: 0 }}
minorGridLines={{ width: 0 }}
minorTickLines={{ width: 0 }}
rowIndex={0} opposedPosition={true}
lineStyle={{ width: 0 }}
majorTickLines={{ width: 0 }}
name='yAxis1'
title='Payment'
labelRotation={0}
labelIntersectAction='Hide'
labelStyle={labelStyle}
titleStyle={titleStyle}
labelFormat='c0'
>
</AxisDirective>
</AxesDirective>
<SeriesCollectionDirective>
<SeriesDirective
xName="yearN"
yName="yearPrincipal"
name="Principal Paid"
width={2}
colorName="rgb(255, 255, 255)"
marker={{ visible: true, width: 10, height: 10 }}
columnWidth={0.425}
type="StackingColumn"
yAxisName="yAxis1"
ref={acc1}
></SeriesDirective>
<SeriesDirective
xName="yearN"
yName="yearInterest"
name="Interest Paid"
width={2}
columnWidth={0.425}
marker={{ visible: true, width: 10, height: 10 }}
type="StackingColumn"
yAxisName="yAxis1"
></SeriesDirective>
<SeriesDirective
xName="yearN"
yName="endingBalance"
name="Balance"
width={2}
columnWidth={0.425}
marker={{ visible: true, width: 10, height: 10, fill: '#60448D' }}
type="Line"
></SeriesDirective>
</SeriesCollectionDirective>
</ChartComponent>
</div>
</div>
<div className="row top-space loan-content max-content">
<h6 className="center-heading">Amortization Schedule</h6>
<div style={{ color: 'white' }}>
<GridComponent
dataSource={yearWiseData}
childGrid={child}
onClick={onclickEvent}
ref={grid}
enableHover={true}
id='scheduleGrid'
columns={columns}
allowTextWrap={true}
>
<Inject services={[DetailRow, Page]} />
</GridComponent>
</div>
</div>
</div >
</div>
)
}

863
src/assets/index.css Normal file
Просмотреть файл

@ -0,0 +1,863 @@
/* body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} */
#abc{
padding-left: 12px;
color: white;
}
#scheduleGrid span{
color:white;
}
#abcd{
color:white;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.e-grid .e-detailrowexpand > div,
.e-grid .e-detailrowcollapse > div {
display: none;
}
.content-space {
display: block;
margin-top: 25px;
margin-bottom: 25px;
width: 100%;
}
.content-space table {
width: 100%;
}
.content-space label {
float: left;
margin-top: 6px;
color: #E7E7E7;
font-size: 16px;
font-family: 'Raleway', sans-serif;
font-weight: 500;
}
.editor-space {
display: flex;
justify-content: left;
float: right;
}
.form-space {
margin-bottom: 25px;
}
.form-space:not(:first-child) {
margin-top: 25px;
}
.navbar {
border-radius: 0;
}
.component-content {
border-radius: 3px;
height: 100%;
}
.parent {
min-height: 85px;
position: relative;
text-align: center;
}
.child {
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
.top-space {
margin-top: 30px;
margin-bottom: 15px;
}
.top-space h6 {
position: relative;
}
.emi-content {
max-width: 634px;
max-height: 660px;
margin: 30px 0 5px 0;
padding: 0 44px;
}
.emi-content h6 {
font-family: 'Raleway', sans-serif;
font-weight: 500;
text-align: center;
}
.emi-content .emi-header {
font-size: 20px;
color: #E7E7E7;
letter-spacing: 0.7px;
line-height: 29px;
}
.emi-content .emi-footer {
font-size: 18px;
color: #989CA9;
margin-top: 5px;
text-align: center;
}
.emi-content h1 {
color: #F5F5F5;
font-size: 32px;
font-family: "Roboto";
font-weight: 500;
text-align: center;
}
.emi-content > div > h6 {
text-align: left;
}
.top-margin {
margin-top: 10px;
}
.bottom-margin {
margin-bottom: 35px;
}
.pie-content {
height: 100%;
padding: 0;
}
.pie-content p {
text-align: center;
font-size: 15px;
font-family: 'Raleway', sans-serif;
font-weight: 500;
color: #989CA9;
}
.pie-content .pie-icon {
height: 21px;
width: 21px;
display: inline-block;
border-radius: 10px;
margin: 0 14px 0 0;
vertical-align: text-top;
}
.pie-content .pie-icon.pie-principal {
background: linear-gradient(#3AC8DC, #5B6BC0);
}
.pie-content .pie-icon.pie-interest {
background: linear-gradient(#F3A55B, #FB6589);
}
.pie-content h5 {
font-size: 18px;
font-family: "Roboto";
font-weight: 500;
color: #F5F5F5;
padding: 5px 0 10px;
text-align: center;
}
.pie-content > div {
margin: 35px 0;
}
.pie-content > div:first-child {
margin-top: 43px;
}
.pie-content > div.pie-total p:first-child {
margin-bottom: 0;
}
.pie-content > div.pie-total p + p {
font-size: 14px;
letter-spacing: 1px;
}
.center-heading {
padding: 10px;
font-size: 20px;
text-align: center;
font-weight: 500;
}
.border-set {
border: 1px solid #e4e2e2;
}
.tenure-value {
display: flex;
padding: 4px 5px 4px 10px;
position: relative;
}
.tenure-value li {
float: left;
}
.tenure-value .e-radio + label::before {
height: 20px;
width: 20px;
border-width: 2px;
}
.tenure-value .e-radio + label::before, .tenure-value .e-radio + label:hover::before {
border-color: #3B9ED4;
background-color: #3A4360;
}
.tenure-value .e-radio + label::after, .tenure-value .e-radio + label:hover::after {
background-color: #3B9ED4 !important;
}
.tenure-value .e-radio + label .e-label {
color: #E7E7E7;
font-size: 16px;
font-family: 'Raleway', sans-serif;
font-weight: 500;
}
.tenure-value .e-radio:focus + label::before {
border-color: #3B9ED4;
background-color: #3A4360;
}
.tenure-value .e-radio:focus + label::after {
background-color: #3B9ED4;
}
.tenure-value > li {
padding-left: 10px;
}
.graph-container {
height: 520px;
padding: 0 33px;
}
li {
list-style: none;
}
.border-unset-left {
border-left: 0;
}
.border-unset-right {
border-right: 0;
}
.main-content {
margin-top: 40px;
max-width: 1300px;
}
.main-content .loan-content {
background-color: #27304c;
color: #E7E7E7;
}
.main-content .e-slider-container .e-scale {
color: #ABABAB;
}
.main-content .e-slider-container .e-scale .e-tick.e-large {
top: 14px;
}
.main-content .e-slider-container .e-scale .e-tick .e-tick-value {
font-family: "Roboto";
font-weight: 400;
font-size: 13px;
color: #ABABAB;
}
.main-content .e-slider-container .e-slider .e-slider-track {
background: #20273E;
border-color: #20273E;
}
.main-content .e-slider-container .e-slider .e-handle {
height: 26px;
width: 26px;
top: calc(50% - 13px);
margin-left: -13px;
}
.main-content .e-slider-container .e-slider .e-handle::before {
content: '';
background: #3B9ED4;
width: 14px;
height: 14px;
position: absolute;
border-radius: 16px;
top: 5px;
left: 5px;
}
.main-content .e-slider-container .e-slider .e-range {
background-color: #3B9ED4;
top: calc(50% - 5px);
}
.main-content .e-slider-container .e-slider .e-slider-track, .main-content .e-slider-container .e-slider .e-range {
height: 12px;
}
.main-content .e-slider-container .e-slider .e-handle, .main-content .e-slider-container .e-slider .e-slider-track, .main-content .e-slider-container .e-slider .e-range {
border-radius: 15px;
}
.main-content .e-input-group.e-control-wrapper:not(.e-success):not(.e-warning):not(.e-error) {
border-color: #475274;
background: #3A4360;
}
.main-content .e-input-group.e-control-wrapper:not(.e-disabled):active:not(.e-success):not(.e-warning):not(.e-error):not(.e-input-focus) {
border-color: #404D75 !important;
}
.main-content .e-input-group.e-control-wrapper .e-input-group-icon {
background: #3A4360;
color: #95979c;
border-color: #475274;
}
.main-content .e-input-group.e-control-wrapper .e-input-group-icon:hover {
background: #404D75;
color: #95979c;
}
.main-content .e-input-group.e-control-wrapper .e-spin-down {
border-right-width: 0;
}
.main-content .e-input-group.e-control-wrapper input.e-input {
font-family: "Roboto";
font-weight: 400;
font-size: 16px;
height: 38px;
background-color: #3A4360;
color: #fff;
}
.main-content .graph-text {
color: #E7E7E7;
font-size: 20px;
font-family: 'Raleway', sans-serif;
font-weight: 500;
letter-spacing: 0.7px;
margin: 0 22px;
display: inline-block;
vertical-align: middle;
}
.main-content .graph-input {
display: inline-block;
margin: 34px 22px;
}
.main-content .e-grid {
border-color: #27304c;
border-radius: 0;
}
.main-content .e-grid .e-row {
cursor: pointer;
}
.main-content .e-grid .e-gridheader {
border-width: 0;
}
.main-content .e-grid div.e-icon-grightarrow, .main-content .e-grid div.e-icon-gdownarrow {
width: 11px;
height: 11px;
border: 1px solid #fff;
margin: auto;
text-indent: 0;
}
.main-content .e-grid .e-icon-grightarrow::before, .main-content .e-grid .e-icon-gdownarrow::before {
position: absolute;
font-size: 13px;
}
.main-content .e-grid div.e-icon-grightarrow::before {
content: '+';
margin: -4px 0 0 -4px;
}
.main-content .e-grid div.e-icon-gdownarrow::before {
content: '-';
margin: -6px 0 0 -2px;
}
.main-content .e-grid .e-headercelldiv {
font-size: 14px;
height: 55px;
line-height: 55px;
font-family: 'Raleway', sans-serif;
font-weight: 500;
white-space: normal;
}
.main-content .e-grid .e-columnheader {
background: linear-gradient(-90deg, #5B6BC0, #3AC8DC);
}
.main-content .e-grid .e-headercell, .main-content .e-grid .e-detailheadercell {
background: transparent;
color: #fff;
}
.main-content .e-grid .e-rowcell, .main-content .e-grid .e-detailrowcollapse, .main-content .e-grid .e-detailrowexpand, .main-content .e-grid .e-detailindentcell, .main-content .e-grid .e-detailrow .e-altrow .e-rowcell {
background: #27304c;
border-width: 0;
font-size: 13px;
font-family: "Roboto";
font-weight: 400;
color:"white"
}
.main-content .e-grid .e-altrow .e-rowcell, .main-content .e-grid .e-altrow .e-detailrowcollapse, .main-content .e-grid .e-altrow .e-detailrowexpand {
background: #313B5A;
}
.main-content .e-grid .e-icons, .main-content .e-grid .e-row .e-rowcell, .main-content .e-grid .e-detailrowcollapse, .main-content .e-grid .e-detailrowexpand {
color: #fff !important ;
}
.main-content .e-grid .e-detailcell {
padding: 0;
border-width: 0;
}
/* .main-content .e-grid.e-gridhover tr[role='row']:not(.e-editedrow):hover .e-rowcell:not(.e-cellselectionbackground):not(.e-active):not(.e-updatedtd):not(.e-indentcell),
.main-content .e-grid.e-gridhover tr[role='row']:hover .e-detailrowcollapse:not(.e-cellselectionbackground):not(.e-active):not(.e-updatedtd):not(.e-indentcell),
.main-content .e-grid.e-gridhover tr[role='row']:hover .e-detailrowexpand:not(.e-cellselectionbackground):not(.e-active):not(.e-updatedtd):not(.e-indentcell) {
background: #404D75 !important;
color: #fff;
} */
/*
.e-detailcell tr[role='row']:hover{
background: #404D75 !important;
} */
.main-content .e-grid [aria-selected] + tr .e-detailindentcell {
border-width: 0;
}
#control-container {
padding: 0px !important;
}
#principal_svg stop {
stop-color: #3AC8DC;
}
#principal_svg stop[offset="0"] {
stop-color: #3AC8DC;
}
#principal_svg stop[offset="1"] {
stop-color: #5B6BC0;
}
#interest_svg stop {
stop-color: #F3A55B;
}
#interest_svg stop[offset="0"] {
stop-color: #e97c11;
}
#interest_svg stop[offset="1"] {
stop-color: #FB6589;
}
.navbar-right {
float: right;
}
.navbar-header {
float: left;
}
.flex-container {
display: flex;
flex-wrap: wrap;
}
.flex-container .col-lg-4 {
width: 33.33333333%;
}
@media (max-width: 500px) {
.flex-container .col-lg-4 {
width: 100%;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: 600;
}
body {
background-color: #162036;
color: #E7E7E7;
}
.left-content {
background-color: #27304c;
max-height: 660px;
margin: 25px 0;
padding: 0 44px;
border-right: 1px solid #475274;
}
.header-style {
background: #27304c;
color: white;
margin: 0;
padding: 15px;
text-align: center;
text-transform: uppercase;
font-size: 26px;
font-family: 'Raleway', sans-serif;
font-weight: 500;
}
.margin-setter {
margin: 35px;
}
.start-setter {
margin: 17px 0;
}
.e-datepicker.e-popup-wrapper {
border-color: #475274;
background-color: #3A4360;
}
.e-datepicker .e-calendar {
background-color: #3A4360;
}
.e-calendar .e-header .e-title, .e-calendar .e-content span, .e-calendar .e-header.e-decade .e-title,
.e-calendar .e-header .e-title:hover {
color: #fff;
}
.e-calendar .e-header .e-icon-container span, .e-calendar .e-header .e-prev:hover > span, .e-calendar .e-header .e-next:hover > span,
.e-calendar .e-header button.e-prev:active span, .e-calendar .e-header button.e-next:active span {
color: #95979c !important;
}
.e-calendar .e-content td.e-selected span.e-day, .e-calendar .e-header .e-prev:active, .e-calendar .e-header .e-next:active {
background: #5B6BC0;
}
.e-calendar .e-content.e-decade tr:first-child .e-cell:first-child span.e-day, .e-calendar .e-content.e-decade tr:last-child .e-cell:last-child span.e-day {
color: #ABABAB;
}
.e-calendar .e-header .e-prev:hover, .e-calendar .e-header .e-next:hover, .e-calendar .e-content td.e-focused-date span.e-day,
.e-calendar .e-content.e-year td:hover span.e-day, .e-calendar .e-content.e-decade td:hover span.e-day,
.e-calendar .e-content.e-year td.e-selected:hover span.e-day, .e-calendar .e-content.e-decade td.e-selected:hover span.e-day {
background: #404D75;
color: #fff;
}
@media (max-width: 319px) {
.container {
min-width: 300px;
}
}
@media (max-width: 576px) {
.header-style {
font-size: 20px;
padding: 13px 0;
}
.container {
padding: 10px;
margin: 0;
}
.container .e-slider-container .e-scale .e-tick .e-tick-value {
font-size: 12px;
}
.top-space {
margin: 10px;
}
.row {
margin-left: 0;
margin-right: 0;
}
.left-content-wrap .loan-content:first-child {
margin-bottom: 10px;
}
.left-content {
padding: 0;
margin: 0;
border-right-width: 0;
}
.left-content .col-lg-12 {
padding: 12px 12px 18px 12px;
}
.left-content .content-space {
margin: 0 0 12px 0;
}
.left-content .content-space td {
display: block;
}
.left-content .content-space label {
font-size: 15px;
margin: 0 0 12px;
}
.left-content .content-space .tenure-value .e-radio + label {
margin: 0;
}
.left-content .content-space .tenure-value .e-radio + label .e-label {
font-size: 13px;
}
.left-content .editor-space {
float: left;
width: 100%;
}
.left-content .form-space {
margin-bottom: 23px;
}
.left-content .form-space:last-child {
margin-bottom: 0;
}
.left-content .e-input-group {
width: 100% !important;
}
.emi-content {
padding: 0;
margin-top: 0;
}
.emi-content .emi-header {
text-align: center;
font-size: 18px;
}
.tenure-value {
padding: 0;
float: none;
}
.emi-content h6 {
font-size: 23px;
}
.emi-content h1 {
font-size: 30px;
}
.emi-content .col-lg-7 {
width: 100%;
float: left;
}
.emi-content .col-lg-5 {
width: 100%;
float: left;
}
.pie-content div {
margin: 10px 0;
text-align: center;
}
.pie-content div:first-child {
margin-top: 0;
}
.pie-content p {
display: inline-block;
margin: 0;
}
.pie-content h5 {
display: inline-block;
margin: 0;
padding: 5px;
}
.pie-content .pie-total span {
display: inline-block;
}
.pie-content .pie-total p {
display: block;
}
.main-content .loan-content .graph-text {
margin: 12px;
font-size: 18px;
}
.main-content .loan-content .graph-input {
padding: 0 12px 12px;
width: 100%;
margin: 0;
}
.center-heading {
font-size: 18px;
}
.graph-container {
padding: 0 2px;
}
}
@media (min-width: 576px) and (max-width: 991px) {
.container {
padding: 0 30px;
width: 100%;
}
.left-content-wrap .loan-content {
width: 100%;
float: left;
margin: 0;
padding-bottom: 25px;
}
.left-content-wrap .loan-content + .loan-content {
margin-top: 30px;
padding-top: 25px;
padding-bottom: 0px;
}
.left-content {
border-right-width: 0;
}
.emi-content {
max-width: 100%;
}
.emi-content .col-lg-7 {
width: 60%;
float: left;
}
.emi-content .col-lg-5 {
width: 40%;
float: left;
}
}
@media (max-width: 700px) {
.main-content .graph-text {
margin-top: 15px;
}
.main-content .graph-input {
margin: 21px;
}
}
@media (min-width: 992px) {
.container {
padding: 0 35px;
width: 100%;
}
.left-content-wrap .loan-content {
width: 50%;
float: left;
margin: 0;
}
.left-content-wrap .loan-content + .loan-content {
margin: 0;
}
.left-content {
border-right-width: 1px;
}
}
@media (min-width: 992px) and (max-width: 1200px) {
.left-content {
min-width: 450px;
padding: 0 20px;
margin-bottom: 40px;
}
.emi-content {
max-width: 100%;
padding: 0 20px;
}
.emi-content .col-lg-7 {
width: 60%;
float: left;
}
.emi-content .col-lg-5 {
width: 40%;
float: left;
}
.emi-content .emi-footer {
margin-top: 15px;
}
.graph-container {
padding: 0 10px;
}
}
@media (min-width: 1200px) and (max-width: 1329px) {
.container {
padding: 0 35px;
}
}
@media (min-width: 1330px) {
.container {
width: 1300px;
}
}
.e-grid#scheduleGrid > .e-gridheader .e-headercontent .e-table colgroup col:first-child,
.e-grid .e-content .e-table#scheduleGrid_content_table > colgroup col:first-child {
width: 0px !important;
}
.e-grid .e-detailrowexpand > div,
.e-grid .e-detailrowcollapse > div {
display: none;
}
.e-grid .e-row .e-row-toggle {
display: inline-block;
color:white;
}
#payment_pieChartPointHover_Border {
opacity: 0;
}
#js-licensing {
display: none !important;
}
.e-childgrid .e-content .e-table{
background-color: #27304c;
}
.e-childgrid .e-content .e-table .e-emptyrow{
color: #27304c !important;
}
.e-grid .e-content .e-table .e-detailrow{
background-color: #27304c ;
}

25812
src/assets/styles.css Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Двоичные данные
src/favicon.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.4 KiB

13
src/index.css Normal file
Просмотреть файл

@ -0,0 +1,13 @@
body {
margin: 0;
/* font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; */
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

15
src/index.tsx Normal file
Просмотреть файл

@ -0,0 +1,15 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<App />
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals

2
src/styles.css Normal file
Просмотреть файл

@ -0,0 +1,2 @@
@import "./assets/styles.css";
@import "./assets/index.css";

26
tsconfig.json Normal file
Просмотреть файл

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}