Skip to content

Commit

Permalink
Moved receipt information to main page
Browse files Browse the repository at this point in the history
Introduced local storage migrations
  • Loading branch information
Wholteza committed Mar 26, 2024
1 parent c7d82b0 commit 7f1bc9b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 37 deletions.
18 changes: 17 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ I have used this project to start learning how to do different types of testing

You can read more about that below.

## Getting started

1. Install Node 20
1. `npm install`
1. `npm run dev`

## Tasks

### Improve process

- [x] User types receipt number as the first field
- [x] User selects the receipt date as the 2nd field
- [ ] Receipt row date is autoset to receipt date upon change
- [ ] Company information is hidden in settings after set
- [x] Logotype is part of company information

## Testing

This is the first time i decided to do extensive automated testing in a frontend application.
Expand All @@ -19,7 +35,7 @@ To keep my unit tests robust and quick to run I am identifying and mocking all e

Since frontend unit testing, in this case a react application, is a different environment than what I'm used to the test code base is going to consistantly evolve as I discover new things.

### Unit
### Unit testing

I have implemented unit tests for all functionality i can easily break out into their own isolated functions.

Expand Down
57 changes: 26 additions & 31 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ChangeEventHandler, useCallback, useMemo, useRef } from "react";
import {
CompanyInformation,
CustomerInformation,
ReceiptInformation,
ReceiptInformationV2,
} from "./types";
import useForm from "./hooks/use-form/use-form";
import useLocalStorage from "./use-local-storage";
Expand All @@ -18,6 +18,7 @@ import {
toReceiptTotalViewModel,
} from "./domain/receipt-total";
import { parseWithDateHydration } from "./helpers/parse-helpers";
import { useLocalStorageMigrations } from "./hooks/use-local-storage-migrations";

const testCompanyInformation: CompanyInformation = {
Identity: {
Expand Down Expand Up @@ -52,8 +53,8 @@ const testCustomerInformation: CustomerInformation = {
},
};

const testReceiptInformation: ReceiptInformation = {
number: "",
const testReceiptInformation: ReceiptInformationV2 = {
receiptNumber: "",
date: new Date(Date.now()),
paymentTerms: "",
};
Expand All @@ -68,12 +69,13 @@ const testReceiptRow: ReceiptRowFormModel = {
const forms = {
company: "company",
customer: "customer",
receipt: "receipt",
rows: "rows",
menu: "menu",
} as const;

const App = () => {
useLocalStorageMigrations(1);

const [companyInformationForm, companyInformation] =
useForm<CompanyInformation>("companyInformation", testCompanyInformation);
const [customerInformationForm, customerInformation] =
Expand All @@ -85,7 +87,7 @@ const App = () => {
ReceiptRowFormModel[]
>("receiptRows", []);
const [receiptInformationForm, receiptInformation] =
useForm<ReceiptInformation>("receiptInformation", testReceiptInformation);
useForm<ReceiptInformationV2>("receiptInformation", testReceiptInformation);
const [currentReceiptRowForm, currentReceiptRow] =
useForm<ReceiptRowFormModel>("currentReceiptRow", testReceiptRow);
const [form, setForm] = useLocalStorage<string>("selectedForm", forms.menu);
Expand Down Expand Up @@ -155,7 +157,9 @@ const App = () => {

return (
<>
{form !== forms.menu ? (
{form === forms.menu ? (
<></>
) : (
<div className="container-without-padding">
<div className="inputs">
<button
Expand All @@ -166,55 +170,38 @@ const App = () => {
</button>
</div>
</div>
) : (
<></>
)}

{form === forms.menu ? (
<div className="container">
<div className="inputs">
<h1>Meny</h1>
<button className="button" onClick={() => setForm(forms.company)}>
Redigera företag
</button>
<div style={{ marginBottom: 20 }}>{receiptInformationForm}</div>
<button className="button" onClick={() => setForm(forms.customer)}>
Redigera kund
</button>
<button className="button" onClick={() => setForm(forms.receipt)}>
Redigera kvitto
</button>
<button className="button" onClick={() => setForm(forms.rows)}>
Redigera rader
</button>
<button className="button" onClick={handleOnClickGeneratePdf}>
Generera PDF
</button>
<button
className="button secondary"
onClick={() => setForm(forms.company)}
>
Redigera företag
</button>
</div>
</div>
) : (
<></>
)}

{form === forms.company ? (
<div className="container">
<div className="inputs">{companyInformationForm}</div>
</div>
) : (
<></>
)}

{form === forms.customer ? (
<div className="container">
<div className="inputs">{customerInformationForm}</div>
</div>
) : (
<></>
)}

{form === forms.receipt ? (
<div className="container">
<div className="inputs">
{receiptInformationForm}
{companyInformationForm}
{file.length ? (
<button
className="button remove-logotype-button"
Expand Down Expand Up @@ -247,6 +234,14 @@ const App = () => {
<></>
)}

{form === forms.customer ? (
<div className="container">
<div className="inputs">{customerInformationForm}</div>
</div>
) : (
<></>
)}

{form === forms.rows ? (
<div className="container">
<div className="inputs">
Expand Down
52 changes: 52 additions & 0 deletions src/hooks/use-local-storage-migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useEffect, useMemo } from "react";
import { ReceiptInformationV1, ReceiptInformationV2 } from "types";
import useLocalStorage from "../use-local-storage";

export const useLocalStorageMigrations = (propVersion: number) => {
const [version, setVersion] = useLocalStorage<number>(
"migrations-version",
0
);

const migrations: { version: number; title: string; migrate: () => void }[] =
useMemo(
() => [
{
version: 0,
title: "Initial migration",
migrate: () => {
/*pass*/
},
},
{
version: 1,
title: "Rename property of number to receiptNumber",
migrate: () => {
const localStorageKey = "formData-receiptInformation";
const rawData = localStorage.getItem(localStorageKey);
if (!rawData) return;

const v1 = JSON.parse(rawData) as ReceiptInformationV1;
const v2 = JSON.parse(rawData) as ReceiptInformationV2;
if (v2.receiptNumber) return;

v2.receiptNumber = v1.number ?? "A1";

localStorage.setItem(localStorageKey, JSON.stringify(v2));
},
},
],
[]
);

useEffect(() => {
if (propVersion > version)
migrations.slice(version + 1, propVersion + 1).forEach((migration) => {
console.log(
`Running migration: ${migration.version}\r\n${migration.title}`
);
migration.migrate();
setVersion(migration.version);
});
}, [migrations, propVersion, setVersion, version]);
};
4 changes: 4 additions & 0 deletions src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ hr {
background-color: $color-primary-light;
box-shadow: 5px 5px 0rem $color-primary;
}
&.secondary {
background-color: $color-secondary-light;
box-shadow: 5px 5px 0rem $color-primary-light;
}
&:hover{
filter: brightness(105%);
cursor: pointer;
Expand Down
1 change: 1 addition & 0 deletions src/internationalization/translate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export const dictionary: { [key: string]: { [key: string]: string } } = {
vatPercentage: "Moms %",
vat: "Moms (SEK)",
total: "Total (inkl. moms)",
receiptNumber: "Kvittonummer",
},
};
8 changes: 7 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ export type CustomerInformation = {
Address: Address;
};

export type ReceiptInformation = {
export type ReceiptInformationV1 = {
date: Date;
paymentTerms: string;
number: string;
};

export type ReceiptInformationV2 = {
date: Date;
paymentTerms: string;
receiptNumber: string;
};
8 changes: 4 additions & 4 deletions src/use-pdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CellConfig, jsPDF, TextOptionsLight } from "jspdf";
import {
CompanyInformation,
CustomerInformation,
ReceiptInformation,
ReceiptInformationV2,
} from "./types";
import { ReceiptRowViewModel } from "./domain/receipt-row";
import { RecieptTotalInformationViewModel } from "./domain/receipt-total";
Expand Down Expand Up @@ -131,7 +131,7 @@ const usePdf = () => {
companyInformation: CompanyInformation,
customerInformation: CustomerInformation,
logotype: string,
receiptInformation: ReceiptInformation,
receiptInformation: ReceiptInformationV2,
receiptRows: ReceiptRowViewModel[],
receiptTotalInformation: RecieptTotalInformationViewModel
) => {
Expand Down Expand Up @@ -269,7 +269,7 @@ const usePdf = () => {
type: "body",
},
{
text: receiptInformation.number,
text: receiptInformation.receiptNumber,
x: columns.right.left,
type: "body",
},
Expand Down Expand Up @@ -443,7 +443,7 @@ const usePdf = () => {
]);

doc.save(
`${receiptInformation.number ?? "kvitto"} - ${
`${receiptInformation.receiptNumber ?? "kvitto"} - ${
customerInformation.Identity.Name
}`
);
Expand Down

0 comments on commit 7f1bc9b

Please sign in to comment.