// Copyright 2020 Blue Static // This program is free software licensed under the GNU General Public License, // version 3.0. The full text of the license can be found in LICENSE.txt. // SPDX-License-Identifier: GPL-3.0-only import { createEffect, createMemo, createState } from 'solid-js'; import { For, Show } from 'solid-js/dom'; import { TaxReturn, Form, Line, FormatType } from 'ustaxlib/core'; import * as Trace from 'ustaxlib/core/Trace'; import { Edge } from 'ustaxlib/core/Trace'; import { graphviz } from 'd3-graphviz'; const S = require('./FormView.css'); interface FormProps { tr: TaxReturn; form: Form; } export default function FormView(props: FormProps) { const lines = createMemo(() => { const keys = Object.keys(props.form.lines); keys.sort((a, b) => a.localeCompare(b, undefined, { numeric: true })); return keys.map(k => props.form.lines[k]); }); return (

Form {props.form.name}

{line => }
); } interface LineProps { tr: TaxReturn; line: Line; } class Formatter { private static _instance: Formatter; private _dollar = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', 'currencySign': 'accounting' } as Intl.NumberFormatOptions); private _percent = new Intl.NumberFormat('en-US', { style: 'percent', maximumFractionDigits: 3 }); private _decimal = new Intl.NumberFormat('en-US', { style: 'decimal', minimumFractionDigits: 5 }); private constructor() {} static getInstance() { if (!Formatter._instance) { Formatter._instance = new Formatter(); } return Formatter._instance; } dollar(value: number): string { return this._dollar.format(value); } percent(value: number): string { return this._percent.format(value); } decimal(value: number): string { return this._decimal.format(value); } string(value: any): string { return JSON.stringify(value, null, 1); } } function formatLine(value: any, line: Line): string { const formatter = Formatter.getInstance(); const formatType = line.options.formatType; if (typeof(value) === 'number') { if (formatType == FormatType.Decimal) { return formatter.decimal(value); } else if (formatType == FormatType.Percent) { return formatter.percent(value); } else if (formatType == FormatType.Dollar || formatType == undefined) { return formatter.dollar(value); } } return formatter.string(value); } function LineView(props: LineProps) { const { tr, line } = props; const [ state, setState ] = createState({ value: undefined as any, error: undefined as any, trace: [] as readonly Edge[], showTrace: false }); createEffect(() => { const newState = { value: undefined, error: undefined, trace: [] as readonly Edge[] }; try { Trace.reset(); newState.value = line.value(tr); } catch (e) { newState.error = e; } newState.trace = Trace.getLastTraceList(); setState(newState); }); const valueDisplay = createMemo(() => { if (state.error) { return {state.error.message}; } return formatLine(state.value, line); }); const toggleTrace = () => setState('showTrace', !state.showTrace); return ( <>
{line.id}
{line.description}
{valueDisplay()}
setState('showTrace', false)} /> ); } interface TraceProps { line: Line; trace: readonly Edge[]; onClose: () => void; } function TraceViewer(props: TraceProps) { const renderGraph = (ref) => { let graph = ''; for (const edge of props.trace) { graph += `"${edge[1]}" -> "${edge[0]}"; `; } graphviz(ref) .zoomScaleExtent([0.1, 1]) .renderDot(`digraph { ${graph} }`, () => { if (ref.querySelector('svg').clientWidth > ref.parentNode.clientWidth) { ref.parentNode.classList.add(S.large); } }); }; return (

Trace {props.line.id}

); }