Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement backend support (deactivated), version updates #31

Merged
merged 7 commits into from
May 30, 2024
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
3,228 changes: 1,682 additions & 1,546 deletions package-lock.json

Large diffs are not rendered by default.

45 changes: 23 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,37 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@coreui/coreui": "^4.2.6",
"@coreui/icons": "^2.1.0",
"@coreui/icons-react": "^2.1.0",
"@coreui/react": "^4.8.0",
"@coreui/coreui": "^5.0.2",
"@coreui/icons": "^3.0.1",
"@coreui/icons-react": "^2.2.1",
"@coreui/react": "^5.1.0",
"@coreui/utils": "^2.0.2",
"@rehooks/local-storage": "^2.4.4",
"dexie": "^3.2.4",
"dexie-react-hooks": "^1.1.6",
"flow-bin": "^0.210.2",
"flow-typed": "^3.8.0",
"i18next": "^23.2.6",
"i18next-browser-languagedetector": "^7.1.0",
"i18next-http-backend": "^2.2.1",
"moment": "^2.29.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^13.0.1",
"@rehooks/local-storage": "^2.4.5",
"dexie": "^4.0.7",
"dexie-react-hooks": "^1.1.7",
"flow-bin": "^0.237.1",
"flow-typed": "^4.0.0",
"i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.5.2",
"moment": "^2.30.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^14.1.2",
"react-qr-reader": "^2.2.1",
"redux":"^4.2.1",
"react-redux": "^8.1.1",
"react-router-dom": "^6.14.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"react-scripts": "^5.0.1",
"redux": "^5.0.1",
"@reduxjs/toolkit": "^2.2.5",
"source-map-explorer": "^2.5.3"
},
"overrides": {
"react":"$react",
"react-dom":"$react-dom"
"react": "$react",
"react-dom": "$react-dom"
},
"devDependencies": {
"sass": "^1.56.2"
"sass": "^1.77.3"
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
Expand Down
2 changes: 1 addition & 1 deletion public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"table": {
"label": "Name",
"value": "Wert",
"billNumber": "Rechnugsnummer",
"billNumber": "Rechnungsnummer",
"date": "Datum",
"grossamount": {
"20percent": "Brutto USt. 20%",
Expand Down
3 changes: 2 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ export default function App() {
<BrowserRouter>
<Suspense fallback={loading}>
<Routes>
<Route path="/*" element={<PageBillReader />} />
<Route path="/" element={<PageBillReader />} />
<Route path="/impressum" element={<PageImprint />} />
<Route path="/about" element={<PageAbout />} />
<Route path="/settings" element={<PageSettings />} />
<Route path="/404" element={<Page404 />} />
<Route path="*" element={<Page404 />} />
</Routes>
</Suspense>
</BrowserRouter>
Expand Down
40 changes: 19 additions & 21 deletions src/components/SettingsContent.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Suspense } from 'react';
import { CCard, CCardBody, CCardText, CCardTitle, CContainer, CListGroup, CRow, CSpinner } from '@coreui/react';
import { CCard, CCardBody, CCardTitle, CContainer, CListGroup, CRow, CSpinner } from '@coreui/react';
import { useTranslation } from 'react-i18next';
import { useUserSettings, writeSwitchUserSetting } from '../util/userSettingsStorage'
import SettingsSwitch from './settings/SettingsSwitch';
Expand All @@ -16,26 +16,24 @@ const SettingsContent = () => {
<CCard>
<CCardBody>
<CCardTitle>{translate('settings.billinfo.title')}</CCardTitle>
<CCardText>
<CListGroup flush>
<SettingsSwitch id="billInfoShowIndividualAmounts"
label={translate('settings.billinfo.showIndividualAmounts')}
defaultChecked={userSettings.showIndividualAmounts}
onChange={() => writeSwitchUserSetting(userSettings, 'showIndividualAmounts')}/>
<SettingsSwitch id="billInfoShowTrustedServiceProvider"
label={translate('settings.billinfo.showTrustedServiceProvider')}
defaultChecked={userSettings.showTrustedServiceProvider}
onChange={() => writeSwitchUserSetting(userSettings, 'showTrustedServiceProvider')}/>
<SettingsSwitch id="billInfoShowCashRegisterNumber"
label={translate('settings.billinfo.showCashRegisterNumber')}
defaultChecked={userSettings.showCashRegisterNumber}
onChange={() => writeSwitchUserSetting(userSettings, 'showCashRegisterNumber')}/>
<SettingsSwitch id="billInfoShowNetAmount"
label={translate('settings.billinfo.showNetAmount')}
defaultChecked={userSettings.showNetAmount}
onChange={() => writeSwitchUserSetting(userSettings, 'showNetAmount')}/>
</CListGroup>
</CCardText>
<CListGroup flush>
<SettingsSwitch id="billInfoShowIndividualAmounts"
label={translate('settings.billinfo.showIndividualAmounts')}
defaultChecked={userSettings.showIndividualAmounts}
onChange={() => writeSwitchUserSetting(userSettings, 'showIndividualAmounts')}/>
<SettingsSwitch id="billInfoShowTrustedServiceProvider"
label={translate('settings.billinfo.showTrustedServiceProvider')}
defaultChecked={userSettings.showTrustedServiceProvider}
onChange={() => writeSwitchUserSetting(userSettings, 'showTrustedServiceProvider')}/>
<SettingsSwitch id="billInfoShowCashRegisterNumber"
label={translate('settings.billinfo.showCashRegisterNumber')}
defaultChecked={userSettings.showCashRegisterNumber}
onChange={() => writeSwitchUserSetting(userSettings, 'showCashRegisterNumber')}/>
<SettingsSwitch id="billInfoShowNetAmount"
label={translate('settings.billinfo.showNetAmount')}
defaultChecked={userSettings.showNetAmount}
onChange={() => writeSwitchUserSetting(userSettings, 'showNetAmount')}/>
</CListGroup>
</CCardBody>
</CCard>
</CRow>
Expand Down
9 changes: 4 additions & 5 deletions src/components/billspage/BillTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@ import { useTranslation } from 'react-i18next';
import { R1TaxRates } from '../../util/bill-parser';
import BillTableRow from './BillTableRow';
import { useUserSettings } from '../../util/userSettingsStorage';
import { matchCompanyByCertSerial } from '../../util/company-matcher'


const BillTable = (props) => {

const translate = useTranslation().t;
const [userSettings] = useUserSettings();
const bill = props.bill;
const amounts = props.bill.amounts;
const amounts = bill.amounts;

const gross20p = amounts?.find(amount => amount?.taxPercentage === R1TaxRates.Rate20)?.fullAmount;
const gross19p = amounts?.find(amount => amount?.taxPercentage === R1TaxRates.Rate19)?.fullAmount;
const gross13p = amounts?.find(amount => amount?.taxPercentage === R1TaxRates.Rate13)?.fullAmount;
const gross10p = amounts?.find(amount => amount?.taxPercentage === R1TaxRates.Rate10)?.fullAmount;
const gross0p = amounts?.find(amount => amount?.taxPercentage === R1TaxRates.Rate0)?.fullAmount;

const sellerName = matchCompanyByCertSerial(bill.certSerialR1);
const sellerName = bill.companyName;

const showGross20p = userSettings.showIndividualAmounts && gross20p > 0;
const showGross10p = userSettings.showIndividualAmounts && gross10p > 0;
Expand All @@ -32,10 +31,10 @@ const BillTable = (props) => {
const showRegisterID = userSettings.showCashRegisterNumber;
const showTrustedServiceProvider = userSettings.showTrustedServiceProvider;

return (
return (
<CContainer>
<CRow>
<CTable hover>
<CTable hover responsive>
<CTableBody>
{sellerName &&
<BillTableRow title={translate('bill.table.company')} content={sellerName}/>
Expand Down
29 changes: 29 additions & 0 deletions src/components/billspage/BillTableRowWithPopup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import CIcon from "@coreui/icons-react";
import { CButton, CPopover, CTableDataCell, CTableHeaderCell, CTableRow } from "@coreui/react";
import * as icon from '@coreui/icons';

const buttonStyle = {
'--cui-btn-padding-x': 0,
'--cui-btn-padding-y': 0,
}

const BillTableRowPopup = (props) => {
return (
<CTableRow onClick={() => {navigator.clipboard.writeText(props.text)}}>
<CTableHeaderCell scope="row">{props.title}</CTableHeaderCell>
<CTableDataCell className="d-flex">
<CPopover
title={props.popupTitle}
content={props.popupText}
placement="bottom"
trigger="focus"
>
<CButton style={buttonStyle} color="link" className=".text-nowrap">{props.text}</CButton>
</CPopover>
<CIcon className="ms-auto" icon={icon.cilClipboard}/>
</CTableDataCell>
</CTableRow>
)
};

export default BillTableRowPopup;
10 changes: 3 additions & 7 deletions src/components/billspage/QrReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,18 @@ export default function QrReaderComponent() {
async function addQrBill (qrBill) {
try {
qrBill.date = qrBill.date.valueOf()
const id = await saveR1Bill(qrBill);

console.log(`Added bill ${qrBill.billNumber} with id ${id}`);
await saveR1Bill(qrBill);
} catch (error) {
console.error(`Failed to add ${qrBill.billNumber} : ${error}`);
}
}

return <>
<div>
return <div>
<QrReader
delay={200}
delay={800}
onError={handleError}
onScan={handleScan}
/>
</div>
</>

}
21 changes: 10 additions & 11 deletions src/components/common/AppHeader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { NavLink } from 'react-router-dom';
import { NavLink, useLocation } from 'react-router-dom';
import {
CContainer,
CHeader,
Expand All @@ -14,7 +14,6 @@ import {
} from '@coreui/react';
import { useTranslation } from 'react-i18next';
import DeleteAllBillsModal from '../billspage/DeleteAllBillsModal';
import { useLocation } from 'react-router-dom';
import { cilHamburgerMenu } from "@coreui/icons";
import CIcon from '@coreui/icons-react';

Expand All @@ -25,18 +24,18 @@ const AppHeader = (props) => {
const location = useLocation().pathname;
const navLinks = [];

navLinks.push({ to: "/", text: translate('header.home') });
navLinks.push({ to: "/settings", text: translate('header.settings') });
navLinks.push({ to: "/about", text: translate('header.about') });
navLinks.push({ key: "home", to: "/", text: translate('header.home') });
navLinks.push({ key: "about", to: "/settings", text: translate('header.settings') });
navLinks.push({ key: "settings", to: "/about", text: translate('header.about') });

return (
<CHeader position="sticky" className="mb-4">
<CRow className='flex-fill justify-content-center' >
<CCollapse className="header-collapse" visible={visible} fluid>
<CCollapse className="header-collapse" visible={visible}>
{navLinks?.map(link =>
<CRow>
<CRow key={link.key}>
<CNavItem className='d-flex justify-content-center align-items-center'>
<CButton variant='ghost' color='dark' size='lg' component={NavLink} to={link.to}>{link.text}</CButton>
<CButton variant='ghost' color='dark' size='lg' as={NavLink} to={link.to}>{link.text}</CButton>
</CNavItem>
</CRow>
)}
Expand All @@ -50,8 +49,8 @@ const AppHeader = (props) => {
{getCurrentPageName(location, navLinks)}
</CHeaderToggler>
{navLinks?.map(link =>
<CNavItem className='d-none d-lg-block'>
<CNavLink to={link.to} component={NavLink}>
<CNavItem key={link.key} className='d-none d-lg-block'>
<CNavLink to={link.to} as={NavLink}>
{link.text}
</CNavLink>
</CNavItem>
Expand All @@ -60,7 +59,7 @@ const AppHeader = (props) => {
</CHeaderNav>
</CNavbar>
{props.showDeleteAll &&
<div class="end-0">
<div className="end-0">
<DeleteAllBillsModal />
</div>
}
Expand Down
12 changes: 4 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import './util/i18n'
import { createRoot } from 'react-dom/client';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);
4 changes: 3 additions & 1 deletion src/scss/style.scss
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
@import "@coreui/coreui/scss/coreui";
@import "@coreui/coreui/scss/coreui";

$enable-shadows: true;
18 changes: 4 additions & 14 deletions src/store.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
import { createStore } from 'redux';
import { configureStore } from '@reduxjs/toolkit'

const initialState = {};

const changeState = (state = initialState, { type, ...rest }) => {
switch (type) {
case 'set':
return { ...state, ...rest };
default:
return state;
}
};

const store = createStore(changeState);
export default store;
export default configureStore({
reducer: {},
})
15 changes: 15 additions & 0 deletions src/util/bill-datatypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class BillContent {
billNumber /*: string*/;
dateMs/*: number*/;
cancellation/*: boolean*/;
companyName/*: string*/;

get date() /*: moment.Moment*/{
return moment(this.dateMs);
Expand Down Expand Up @@ -97,3 +98,17 @@ export class R1TrustedSupplier {
}
}
}

export class CompanyInfo {
shopName /*: string */;
companyName /*: string */;
certId /*: string */;
uid /*: string */;

constructor(company) {
this.shopName = company.shopName;
this.companyName = company.companyName;
this.certId = company.certId;
this.uid = company.uid;
}
}
16 changes: 3 additions & 13 deletions src/util/company-matcher.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import companyMappings from './data/companyMapping.json';
import ApiClient from './qrBackendClient';

const uidMapping = companyMappings.uidMap;
const serialMapping = companyMappings.serialMap

export function matchCompanyByCertSerial(certSerial /*: string*/){

const uidRegExp = new RegExp("^U:ATU\\d{8}-\\d+$","i");

if (uidRegExp.test(certSerial)) {
const uid = certSerial.slice(2,13);
return uidMapping[uid];
}

return serialMapping[certSerial];
export async function matchCompanyByCertSerial(certSerial /*: string*/){
return ApiClient.matchCompanyByQrCertSerial(certSerial).then(data => {return data.companyName});
}
8 changes: 8 additions & 0 deletions src/util/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const config = {
"api": {
"url": "http://localhost:8080/api",
"active": false
}
}

export default config;
Loading
Loading