@star-insure/sdk 1.0.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -12
- package/src/components/common/Button.tsx +60 -0
- package/src/components/common/Card.tsx +14 -0
- package/src/components/common/Modal.tsx +54 -0
- package/src/components/common/Pagination.tsx +77 -0
- package/src/components/common/ToastItem.tsx +54 -0
- package/src/components/common/Toasts.tsx +16 -0
- package/src/components/common/index.ts +15 -0
- package/src/components/forms/DateOfBirthField.tsx +84 -0
- package/src/components/forms/Errors.tsx +32 -0
- package/src/components/forms/FormTester.tsx +170 -0
- package/src/components/forms/MoneyField.tsx +45 -0
- package/src/components/forms/RegistrationSearchField.tsx +187 -0
- package/src/components/forms/index.ts +13 -0
- package/src/components/index.ts +3 -0
- package/src/components/tables/Table.tsx +19 -0
- package/src/components/tables/TableActions.tsx +14 -0
- package/src/components/tables/TableBody.tsx +14 -0
- package/src/components/tables/TableCell.tsx +14 -0
- package/src/components/tables/TableHead.tsx +14 -0
- package/src/components/tables/TableHeader.tsx +49 -0
- package/src/components/tables/TableRow.tsx +17 -0
- package/src/components/tables/index.ts +17 -0
- package/src/index.ts +1 -0
- package/src/lib/addressFinder.tsx +100 -0
- package/src/lib/auth.tsx +8 -0
- package/src/lib/calculateAge.ts +19 -0
- package/src/lib/clickOutside.tsx +24 -0
- package/src/lib/index.ts +9 -0
- package/src/lib/inertiaOptions.tsx +27 -0
- package/src/lib/localStorage.tsx +41 -0
- package/src/lib/quoteRequestForm.tsx +144 -0
- package/src/lib/quoteRequestOptions.tsx +21 -0
- package/src/lib/toast.tsx +55 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -8
- package/dist/lib/dates.d.ts +0 -8
- package/dist/lib/index.d.ts +0 -3
- package/dist/lib/money.d.ts +0 -32
- package/dist/lib/vehicles.d.ts +0 -2
- package/dist/sdk.cjs.development.js +0 -161
- package/dist/sdk.cjs.development.js.map +0 -1
- package/dist/sdk.cjs.production.min.js +0 -2
- package/dist/sdk.cjs.production.min.js.map +0 -1
- package/dist/sdk.esm.js +0 -148
- package/dist/sdk.esm.js.map +0 -1
- package/dist/types/api/auth.d.ts +0 -9
- package/dist/types/api/enums.d.ts +0 -4
- package/dist/types/api/index.d.ts +0 -31
- package/dist/types/api/responses/claimRequestActions.d.ts +0 -12
- package/dist/types/api/responses/index.d.ts +0 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/misc/index.d.ts +0 -8
- package/dist/types/misc/inertia.d.ts +0 -8
- package/dist/types/models/auth/Group.d.ts +0 -10
- package/dist/types/models/auth/Permission.d.ts +0 -4
- package/dist/types/models/auth/Role.d.ts +0 -6
- package/dist/types/models/auth/User.d.ts +0 -12
- package/dist/types/models/auth/index.d.ts +0 -4
- package/dist/types/models/claims/ClaimRequest.d.ts +0 -287
- package/dist/types/models/claims/index.d.ts +0 -1
- package/dist/types/models/index.d.ts +0 -6
- package/dist/types/models/oracle/Risk.d.ts +0 -8
- package/dist/types/models/oracle/TableData.d.ts +0 -9
- package/dist/types/models/oracle/index.d.ts +0 -2
- package/dist/types/models/payments/Gateways.d.ts +0 -1
- package/dist/types/models/payments/Payment.d.ts +0 -35
- package/dist/types/models/payments/index.d.ts +0 -2
- package/dist/types/models/quotes/Club.d.ts +0 -4
- package/dist/types/models/quotes/EmailContentOption.d.ts +0 -7
- package/dist/types/models/quotes/InformationRequest.d.ts +0 -34
- package/dist/types/models/quotes/Lead.d.ts +0 -17
- package/dist/types/models/quotes/MotorwebVehicle.d.ts +0 -120
- package/dist/types/models/quotes/PolicyBenefit.d.ts +0 -16
- package/dist/types/models/quotes/PolicyEnhancement.d.ts +0 -11
- package/dist/types/models/quotes/PostalAddress.d.ts +0 -7
- package/dist/types/models/quotes/PromoCode.d.ts +0 -18
- package/dist/types/models/quotes/QuoteRequest.d.ts +0 -88
- package/dist/types/models/quotes/QuoteRequestDeclaration.d.ts +0 -22
- package/dist/types/models/quotes/QuoteRequestForm.d.ts +0 -112
- package/dist/types/models/quotes/QuoteRequestIncident.d.ts +0 -5
- package/dist/types/models/quotes/QuoteRequestLog.d.ts +0 -10
- package/dist/types/models/quotes/QuoteRequestOptions.d.ts +0 -59
- package/dist/types/models/quotes/QuoteRequestPurchaseOption.d.ts +0 -35
- package/dist/types/models/quotes/QuoteRequestReferrer.d.ts +0 -7
- package/dist/types/models/quotes/QuoteRequestReferrerCategory.d.ts +0 -4
- package/dist/types/models/quotes/QuoteRequestVehicle.d.ts +0 -20
- package/dist/types/models/quotes/QuoteRequestVehicleDriver.d.ts +0 -10
- package/dist/types/models/quotes/RedbookVehicle.d.ts +0 -55
- package/dist/types/models/quotes/StreetAddress.d.ts +0 -8
- package/dist/types/models/quotes/index.d.ts +0 -22
- package/dist/types/models/sms-messages/SmsContentOption.d.ts +0 -7
- package/dist/types/models/sms-messages/SmsMessage.d.ts +0 -18
- package/dist/types/models/sms-messages/SmsMessageReply.d.ts +0 -10
- package/dist/types/models/sms-messages/index.d.ts +0 -3
package/package.json
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"name": "@star-insure/sdk",
|
|
3
3
|
"description": "The SDK for Star Insure client apps with shared helper functions and TypeScript definitions.",
|
|
4
4
|
"author": "alexclark_nz",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.1.2",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/star-insure/sdk"
|
|
10
10
|
},
|
|
11
|
-
"main": "
|
|
12
|
-
"typings": "
|
|
11
|
+
"main": "./index.js",
|
|
12
|
+
"typings": "./index.d.ts",
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|
|
15
15
|
"src"
|
|
@@ -18,14 +18,8 @@
|
|
|
18
18
|
"node": ">=10"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
|
-
"dev": "
|
|
22
|
-
"
|
|
23
|
-
"build": "tsdx build",
|
|
24
|
-
"test": "tsdx test",
|
|
25
|
-
"lint": "tsdx lint",
|
|
26
|
-
"prepare": "tsdx build",
|
|
27
|
-
"size": "size-limit",
|
|
28
|
-
"analyze": "size-limit --why"
|
|
21
|
+
"dev": "tsc",
|
|
22
|
+
"build": "tsc"
|
|
29
23
|
},
|
|
30
24
|
"husky": {
|
|
31
25
|
"hooks": {
|
|
@@ -51,6 +45,10 @@
|
|
|
51
45
|
],
|
|
52
46
|
"devDependencies": {
|
|
53
47
|
"@size-limit/preset-small-lib": "^7.0.8",
|
|
48
|
+
"@types/lodash-es": "^4.17.6",
|
|
49
|
+
"@types/react": "^18.0.19",
|
|
50
|
+
"@types/react-dom": "^18.0.6",
|
|
51
|
+
"@types/uuid": "^8.3.4",
|
|
54
52
|
"husky": "^8.0.1",
|
|
55
53
|
"np": "^7.6.1",
|
|
56
54
|
"size-limit": "^7.0.8",
|
|
@@ -59,7 +57,13 @@
|
|
|
59
57
|
"typescript": "^3.9.10"
|
|
60
58
|
},
|
|
61
59
|
"dependencies": {
|
|
60
|
+
"@headlessui/react": "^1.6.3",
|
|
62
61
|
"@inertiajs/inertia": "^0.11.0",
|
|
63
|
-
"
|
|
62
|
+
"@inertiajs/inertia-react": "^0.8.0",
|
|
63
|
+
"date-fns": "^2.28.0",
|
|
64
|
+
"lodash-es": "^4.17.21",
|
|
65
|
+
"react": "^18.2.0",
|
|
66
|
+
"react-dom": "^18.2.0",
|
|
67
|
+
"uuid": "^9.0.0"
|
|
64
68
|
}
|
|
65
69
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "@inertiajs/inertia-react";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
className?: string;
|
|
6
|
+
href?: string;
|
|
7
|
+
target?: '_blank' | '_self';
|
|
8
|
+
onClick?: Function;
|
|
9
|
+
type?: 'button' | 'submit';
|
|
10
|
+
status?: 'primary' | 'danger' | 'warning' | 'info' | 'default';
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
as?: 'link' | 'button' | 'a';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function Button({ className, href, target, onClick, type, children, status = 'default', disabled = false, as }: Props) {
|
|
17
|
+
const baseClasses = 'font-black inline-flex items-center gap-3 justify-center text-white text-center px-5 py-2 rounded-md min-w-[120px] transition-all hover:opacity-75';
|
|
18
|
+
|
|
19
|
+
const statusClass = status === 'primary' && 'bg-teal'
|
|
20
|
+
|| status === 'danger' && 'bg-red-500'
|
|
21
|
+
|| status === 'warning' && 'bg-yellow-400'
|
|
22
|
+
|| status === 'info' && 'bg-blue-400'
|
|
23
|
+
|| 'bg-gray-600';
|
|
24
|
+
|
|
25
|
+
const classes = `${className ?? ''} ${baseClasses} ${statusClass}`;
|
|
26
|
+
|
|
27
|
+
if (onClick) {
|
|
28
|
+
return (
|
|
29
|
+
<button className={classes} type={type ?? 'button'} onClick={(e: React.MouseEvent) => onClick(e)} disabled={disabled}>
|
|
30
|
+
{children}
|
|
31
|
+
</button>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (type) {
|
|
36
|
+
return (
|
|
37
|
+
<button className={classes} type={type ?? 'button'} disabled={disabled}>
|
|
38
|
+
{children}
|
|
39
|
+
</button>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (href) {
|
|
44
|
+
if (href.includes('http') || target === '_blank' || as === 'a') {
|
|
45
|
+
return (
|
|
46
|
+
<a href={href} target={target ?? '_self'} className={classes}>
|
|
47
|
+
{children}
|
|
48
|
+
</a>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Link href={href} className={classes}>
|
|
54
|
+
{children}
|
|
55
|
+
</Link>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return <p className="text-red-500 text-sm">[Invalid button]</p>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
className?: string;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function Card({ className, children }: Props) {
|
|
9
|
+
return (
|
|
10
|
+
<div className={`${className ?? ''} flex flex-col items-start bg-white rounded-md shadow border border-gray-200 p-4 md:p-6`}>
|
|
11
|
+
{children}
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Fragment } from 'react'
|
|
3
|
+
import { Dialog, Transition } from '@headlessui/react'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
isActive?: boolean;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
title?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function Modal({ children, isActive = false, onClose, title }: Props) {
|
|
13
|
+
return (
|
|
14
|
+
<Transition.Root show={isActive} as={Fragment}>
|
|
15
|
+
<Dialog as="div" className="fixed z-[110] inset-0 overflow-y-auto" onClose={onClose}>
|
|
16
|
+
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
|
17
|
+
<Transition.Child
|
|
18
|
+
as={Fragment}
|
|
19
|
+
enter="ease-out duration-300"
|
|
20
|
+
enterFrom="opacity-0"
|
|
21
|
+
enterTo="opacity-100"
|
|
22
|
+
leave="ease-in duration-200"
|
|
23
|
+
leaveFrom="opacity-100"
|
|
24
|
+
leaveTo="opacity-0"
|
|
25
|
+
>
|
|
26
|
+
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
|
27
|
+
</Transition.Child>
|
|
28
|
+
|
|
29
|
+
<Transition.Child
|
|
30
|
+
as={Fragment}
|
|
31
|
+
enter="ease-out duration-300"
|
|
32
|
+
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
33
|
+
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
|
34
|
+
leave="ease-in duration-200"
|
|
35
|
+
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
|
36
|
+
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
37
|
+
>
|
|
38
|
+
<div className="w-full align-start inline-block bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-3xl sm:p-6">
|
|
39
|
+
<div className={`flex gap-4 mb-4 text-asphalt ${title ? 'border-b-2 border-asphalt pb-4' : ''}`}>
|
|
40
|
+
{title && <h3 className="font-black text-lg">{title}</h3>}
|
|
41
|
+
<button type="button" onClick={onClose} className="ml-auto transition-all hover:opacity-50">
|
|
42
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
43
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
44
|
+
</svg>
|
|
45
|
+
</button>
|
|
46
|
+
</div>
|
|
47
|
+
<div>{children}</div>
|
|
48
|
+
</div>
|
|
49
|
+
</Transition.Child>
|
|
50
|
+
</div>
|
|
51
|
+
</Dialog>
|
|
52
|
+
</Transition.Root>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "@inertiajs/inertia-react";
|
|
3
|
+
import type { Meta } from "../../types";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
className?: string;
|
|
7
|
+
meta: Meta;
|
|
8
|
+
showPerPageSelector?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function Pagination({ meta, className, showPerPageSelector = false }: Props) {
|
|
12
|
+
const { current_page, total, per_page } = meta;
|
|
13
|
+
const page_count = Math.ceil(total / per_page);
|
|
14
|
+
|
|
15
|
+
function getNextPageLink() {
|
|
16
|
+
if (typeof window !== 'undefined') {
|
|
17
|
+
const search = new URLSearchParams(window.location.search);
|
|
18
|
+
search.set('page', String(current_page + 1));
|
|
19
|
+
|
|
20
|
+
return `?${search.toString()}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getPrevPageLink() {
|
|
27
|
+
if (typeof window !== 'undefined') {
|
|
28
|
+
const search = new URLSearchParams(window.location.search);
|
|
29
|
+
search.set('page', String(current_page - 1));
|
|
30
|
+
|
|
31
|
+
return `?${search.toString()}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const nextPageLink = getNextPageLink();
|
|
38
|
+
const prevPageLink = getPrevPageLink();
|
|
39
|
+
|
|
40
|
+
function handlePerPageChange(e: React.SyntheticEvent<HTMLSelectElement>) {
|
|
41
|
+
const search = new URLSearchParams(window?.location.search);
|
|
42
|
+
search.set('limit', e.currentTarget.value);
|
|
43
|
+
search.set('page', '1');
|
|
44
|
+
|
|
45
|
+
window.location.href = `?${search.toString()}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={`${className ?? ''}`}>
|
|
50
|
+
<nav className="font-bold flex justify-between items-center gap-6">
|
|
51
|
+
<Link href={prevPageLink} className="flex items-center gap-2" disabled={current_page === 1}>
|
|
52
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
|
53
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
|
54
|
+
</svg>
|
|
55
|
+
Prev
|
|
56
|
+
</Link>
|
|
57
|
+
<div className="flex gap-6 items-center">
|
|
58
|
+
<p>Page {current_page} of {page_count}</p>
|
|
59
|
+
{showPerPageSelector ? (
|
|
60
|
+
<select value={per_page} onChange={handlePerPageChange}>
|
|
61
|
+
<option value="10">10 per page</option>
|
|
62
|
+
<option value="25">25 per page</option>
|
|
63
|
+
<option value="50">50 per page</option>
|
|
64
|
+
<option value="100">100 per page</option>
|
|
65
|
+
</select>
|
|
66
|
+
) : ''}
|
|
67
|
+
</div>
|
|
68
|
+
<Link href={nextPageLink} className="flex items-center gap-2" disabled={current_page === page_count}>
|
|
69
|
+
Next
|
|
70
|
+
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2">
|
|
71
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
|
72
|
+
</svg>
|
|
73
|
+
</Link>
|
|
74
|
+
</nav>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Transition } from '@headlessui/react';
|
|
3
|
+
import type { Toast } from '../../types';
|
|
4
|
+
import { useToast } from '../../lib/toast';
|
|
5
|
+
|
|
6
|
+
export default function ToastItem({ _id = '', message, status = 'default' }: Toast) {
|
|
7
|
+
const { removeToast } = useToast();
|
|
8
|
+
|
|
9
|
+
const defaultClasses = 'w-full min-w-[250px] p-4 shadow flex justify-between items-center font-black rounded-md not:';
|
|
10
|
+
|
|
11
|
+
const statusClasses = status === 'success' && 'bg-teal text-white'
|
|
12
|
+
|| status === 'error' && 'bg-red-500 text-white'
|
|
13
|
+
|| status === 'warning' && 'bg-yellow-400 text-white'
|
|
14
|
+
|| 'bg-white text-asphalt';
|
|
15
|
+
|
|
16
|
+
const classes = `${defaultClasses} ${statusClasses}`;
|
|
17
|
+
|
|
18
|
+
function handleClick() {
|
|
19
|
+
removeToast(_id);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Transition
|
|
24
|
+
show={true}
|
|
25
|
+
appear={true}
|
|
26
|
+
enter="transition-all duration-300"
|
|
27
|
+
enterFrom="opacity-0 translate-y-4"
|
|
28
|
+
enterTo="opacity-100 translate-y-0"
|
|
29
|
+
leave="transition-all duration-300"
|
|
30
|
+
leaveFrom="opacity-100 translate-y-0"
|
|
31
|
+
leaveTo="opacity-0 translate-y-2"
|
|
32
|
+
>
|
|
33
|
+
<div className={classes}>
|
|
34
|
+
<p>{message}</p>
|
|
35
|
+
<button className="" onClick={handleClick} title="Close message">
|
|
36
|
+
<svg
|
|
37
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
38
|
+
fill="none"
|
|
39
|
+
viewBox="0 0 24 24"
|
|
40
|
+
stroke="currentColor"
|
|
41
|
+
className="h-6 w-6"
|
|
42
|
+
>
|
|
43
|
+
<path
|
|
44
|
+
strokeLinecap="round"
|
|
45
|
+
strokeLinejoin="round"
|
|
46
|
+
strokeWidth="2"
|
|
47
|
+
d="M6 18L18 6M6 6l12 12"
|
|
48
|
+
/>
|
|
49
|
+
</svg>
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
</Transition>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Toast } from "../../types";
|
|
3
|
+
import { useToast } from "../../lib/toast";
|
|
4
|
+
import ToastItem from "./ToastItem";
|
|
5
|
+
|
|
6
|
+
export default function Toasts() {
|
|
7
|
+
const { toasts } = useToast();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div className="fixed bottom-4 right-4 z-[110] flex flex-col gap-6">
|
|
11
|
+
{toasts.map((toast: Toast) => (
|
|
12
|
+
<ToastItem {...toast} key={toast._id} />
|
|
13
|
+
))}
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Button from './Button';
|
|
2
|
+
import Card from './Card';
|
|
3
|
+
import Pagination from './Pagination';
|
|
4
|
+
import ToastItem from './ToastItem';
|
|
5
|
+
import Toasts from './Toasts';
|
|
6
|
+
import Modal from './Modal';
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
Button,
|
|
10
|
+
Card,
|
|
11
|
+
Pagination,
|
|
12
|
+
ToastItem,
|
|
13
|
+
Toasts,
|
|
14
|
+
Modal,
|
|
15
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { padStart } from "lodash-es";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
value?: string;
|
|
6
|
+
onChange: (newValue: string) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function DateOfBirthField({ value, onChange }: Props) {
|
|
10
|
+
const [dateOfBirth, setDateOfBirth] = React.useState({
|
|
11
|
+
day: value?.split("-")[2] || '',
|
|
12
|
+
month: value?.split("-")[1] || '',
|
|
13
|
+
year: value?.split("-")[0] || '',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const dayOptions = [...Array.from(Array(31).keys())].map(value => {
|
|
17
|
+
return padStart(`${value + 1}`, 2, '0');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
21
|
+
const monthOptions = [...Array.from(Array(12).keys())].map(value => {
|
|
22
|
+
return {
|
|
23
|
+
title: months[value],
|
|
24
|
+
value: padStart(`${value + 1}`, 2, '0')
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const thisYear = new Date().getFullYear();
|
|
29
|
+
const yearOptions = [...Array.from(Array(100).keys())].map(value => {
|
|
30
|
+
return (thisYear - value - 16).toString();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function handleSelectChange(e: React.FormEvent<HTMLSelectElement>) {
|
|
34
|
+
const { name, value } = e.currentTarget;
|
|
35
|
+
|
|
36
|
+
const newDob = {
|
|
37
|
+
...dateOfBirth,
|
|
38
|
+
[name]: value,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Set local state
|
|
42
|
+
setDateOfBirth(newDob);
|
|
43
|
+
|
|
44
|
+
// Format the date for the API
|
|
45
|
+
const formattedDate = `${newDob.year}-${newDob.month}-${newDob.day}`;
|
|
46
|
+
|
|
47
|
+
// Call the upstream prop if we have all of the date parts
|
|
48
|
+
if (Object.values(newDob).every(value => value !== '')) {
|
|
49
|
+
onChange(formattedDate);
|
|
50
|
+
} else {
|
|
51
|
+
// Otherwise, clear the value
|
|
52
|
+
onChange('');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<label className="w-full">
|
|
58
|
+
<span className="relative mr-auto">
|
|
59
|
+
<span>Date of birth</span>
|
|
60
|
+
</span>
|
|
61
|
+
|
|
62
|
+
<span className="flex space-x-4 border border-gray-300 rounded-lg mt-1 bg-white">
|
|
63
|
+
<select name="day" value={dateOfBirth.day} className="flex-grow focus:outline-none border-0" onChange={handleSelectChange} required>
|
|
64
|
+
<option value="">Day</option>
|
|
65
|
+
{dayOptions.map(option => (
|
|
66
|
+
<option key={option} value={option}>{option}</option>
|
|
67
|
+
))}
|
|
68
|
+
</select>
|
|
69
|
+
<select name="month" value={dateOfBirth.month} className="flex-grow focus:outline-none border-0" onChange={handleSelectChange} required>
|
|
70
|
+
<option value="">Month</option>
|
|
71
|
+
{monthOptions.map(option => (
|
|
72
|
+
<option key={option.value} value={option.value}>{option.title}</option>
|
|
73
|
+
))}
|
|
74
|
+
</select>
|
|
75
|
+
<select name="year" value={dateOfBirth.year} className="flex-grow focus:outline-none border-0" onChange={handleSelectChange} required>
|
|
76
|
+
<option value="">Year</option>
|
|
77
|
+
{yearOptions.map(option => (
|
|
78
|
+
<option key={option} value={option}>{option}</option>
|
|
79
|
+
))}
|
|
80
|
+
</select>
|
|
81
|
+
</span>
|
|
82
|
+
</label>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ErrorBag, Errors } from "@inertiajs/inertia"
|
|
3
|
+
import { Card } from "../common";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
heading?: string;
|
|
7
|
+
errors?: Errors & ErrorBag;
|
|
8
|
+
renderKeys?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function Errors({ heading = 'There was an error with your submission.', errors = {}, renderKeys = false, className = '' }: Props) {
|
|
13
|
+
if (Object.values(errors).length === 0) {
|
|
14
|
+
return <></>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<aside className={`${className} col-span-full`}>
|
|
19
|
+
<Card className="border border-red-500 !bg-red-50">
|
|
20
|
+
<h2 className="font-black text-red-500 mb-2">{heading}</h2>
|
|
21
|
+
<ul className="space-y-2 list-disc ml-4">
|
|
22
|
+
{Object.entries(errors).map(([field, message]) => (
|
|
23
|
+
<li className="font-bold text-red-500" key={field}>
|
|
24
|
+
{renderKeys && <strong>{field}: </strong>}
|
|
25
|
+
{ message }
|
|
26
|
+
</li>
|
|
27
|
+
))}
|
|
28
|
+
</ul>
|
|
29
|
+
</Card>
|
|
30
|
+
</aside>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button } from '../common';
|
|
3
|
+
import { useQuoteRequestForm } from '../../lib';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
populatePurchaseOptions: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function FormTester({ populatePurchaseOptions = false }: Props) {
|
|
10
|
+
const { form } = useQuoteRequestForm();
|
|
11
|
+
const [keys, setKeys] = React.useState<string[]>([]);
|
|
12
|
+
const [isDev, setDev] = React.useState<boolean>(false);
|
|
13
|
+
|
|
14
|
+
function handlePopulate() {
|
|
15
|
+
form?.setData(prevData => ({
|
|
16
|
+
...prevData,
|
|
17
|
+
first_name: 'TEST',
|
|
18
|
+
last_name: 'TEST',
|
|
19
|
+
email: 'dev@sual.co.nz',
|
|
20
|
+
phone: '021 234 5678',
|
|
21
|
+
mobile: '021 234 5678',
|
|
22
|
+
dob: '1990-01-01',
|
|
23
|
+
licence: 'Other',
|
|
24
|
+
licence_other: 'Test',
|
|
25
|
+
club_id: 50,
|
|
26
|
+
club_membership_number: '12345',
|
|
27
|
+
street_address: {
|
|
28
|
+
address: '123 Street Name',
|
|
29
|
+
unit: 'Level 1',
|
|
30
|
+
suburb: 'Suburb',
|
|
31
|
+
city: 'Auckland',
|
|
32
|
+
post_code: '1234',
|
|
33
|
+
},
|
|
34
|
+
promo_code: 'TEST',
|
|
35
|
+
declaration: {
|
|
36
|
+
had_incident: true,
|
|
37
|
+
incidents: [{
|
|
38
|
+
description: 'Lorem ipsum dolor sit amet.',
|
|
39
|
+
month: 'January',
|
|
40
|
+
year: '2020',
|
|
41
|
+
}],
|
|
42
|
+
has_demerit_points: true,
|
|
43
|
+
demerit_points: '1-24',
|
|
44
|
+
has_lost_licence: true,
|
|
45
|
+
lost_licence_details: 'Lorem ipsum dolor sit amet.',
|
|
46
|
+
was_refused_insurance: true,
|
|
47
|
+
refused_insurance_details: 'Lorem ipsum dolor sit amet.',
|
|
48
|
+
has_criminal_conviction: true,
|
|
49
|
+
criminal_conviction_details: 'Lorem ipsum dolor sit amet.',
|
|
50
|
+
has_vehicle_modifications: true,
|
|
51
|
+
vehicle_modifications_details: 'Lorem ipsum dolor sit amet.',
|
|
52
|
+
has_previous_insurer: true,
|
|
53
|
+
previous_insurer_details: 'AA',
|
|
54
|
+
previous_insurer_expires_at: '2020-01-01',
|
|
55
|
+
additional_details: 'I am a robot, beep boop. Please ignore this submission.',
|
|
56
|
+
},
|
|
57
|
+
vehicles: [
|
|
58
|
+
{
|
|
59
|
+
make: 'Tesla',
|
|
60
|
+
model: 'Cybertruck',
|
|
61
|
+
year: '2023',
|
|
62
|
+
registration: 'ELMUSK',
|
|
63
|
+
vehicle_type: 'car',
|
|
64
|
+
product: 'star-enthusiast-prestige-everyday-plus',
|
|
65
|
+
value: 100000,
|
|
66
|
+
is_heavy: false,
|
|
67
|
+
usage: 'Childrens car',
|
|
68
|
+
storage_location: 'Carport',
|
|
69
|
+
has_financially_interested_party: true,
|
|
70
|
+
financially_interested_party_detail: 'MTA',
|
|
71
|
+
owned_duration: 'Less than 12 months',
|
|
72
|
+
drivers: [
|
|
73
|
+
{
|
|
74
|
+
first_name: 'X Æ',
|
|
75
|
+
last_name: 'A-12',
|
|
76
|
+
dob: '2020-05-04',
|
|
77
|
+
licence: 'Other',
|
|
78
|
+
licence_other: 'None',
|
|
79
|
+
relationship: 'Child',
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
purchase_options: populatePurchaseOptions ? [
|
|
85
|
+
{
|
|
86
|
+
premium_type: 'annual',
|
|
87
|
+
level_of_insurance_id: 12,
|
|
88
|
+
authorised_drivers: 'TEST',
|
|
89
|
+
excess_details: 'TEST',
|
|
90
|
+
terms: 'TEST',
|
|
91
|
+
description: 'This is a test purchase option',
|
|
92
|
+
premium: 100000,
|
|
93
|
+
monthly_premium: 8500,
|
|
94
|
+
show_monthly: true,
|
|
95
|
+
fsl: 100,
|
|
96
|
+
benefits: [{id: 2}, {id: 8}],
|
|
97
|
+
benefit_template_id: 3,
|
|
98
|
+
sort_order: 1,
|
|
99
|
+
enhancements: [
|
|
100
|
+
{ name: 'Test enhancement', premium: 2500, disable_rounding: false, description: 'Test enhancement', auto_select: true },
|
|
101
|
+
{ name: 'Test enhancement', premium: 5000, disable_rounding: false, description: 'Test enhancement', auto_select: false }
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
premium_type: 'total-due',
|
|
106
|
+
level_of_insurance_id: 13,
|
|
107
|
+
authorised_drivers: 'TEST',
|
|
108
|
+
excess_details: 'TEST',
|
|
109
|
+
terms: 'TEST',
|
|
110
|
+
description: 'This is a test purchase option',
|
|
111
|
+
premium: 100000,
|
|
112
|
+
show_monthly: false,
|
|
113
|
+
fsl: 100,
|
|
114
|
+
benefits: [{id: 2}, {id: 8}],
|
|
115
|
+
benefit_template_id: 3,
|
|
116
|
+
sort_order: 2,
|
|
117
|
+
enhancements: [
|
|
118
|
+
{ name: 'Test enhancement', premium: 2500, disable_rounding: false, description: 'Test enhancement', auto_select: true },
|
|
119
|
+
{ name: 'Test enhancement', premium: 5000, disable_rounding: false, description: 'Test enhancement', auto_select: false }
|
|
120
|
+
],
|
|
121
|
+
}
|
|
122
|
+
] : [],
|
|
123
|
+
}))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
127
|
+
if (e.key === 'Escape') {
|
|
128
|
+
return setKeys([]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
setKeys(prevKeys => [...prevKeys, e.key]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
React.useEffect(() => {
|
|
135
|
+
// Detect when the user has typed the word "debug"
|
|
136
|
+
if (keys.join('') === 'debug') {
|
|
137
|
+
handlePopulate();
|
|
138
|
+
}
|
|
139
|
+
}, [keys]);
|
|
140
|
+
|
|
141
|
+
React.useEffect(() => {
|
|
142
|
+
if (typeof window !== 'undefined') {
|
|
143
|
+
if (window.location.href.includes('dev')
|
|
144
|
+
|| window.location.href.includes('localhost')
|
|
145
|
+
|| window.location.href.includes('test')
|
|
146
|
+
|| window.location.href.includes('local')
|
|
147
|
+
) {
|
|
148
|
+
setDev(true);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
window.addEventListener('keydown', (e: KeyboardEvent) => handleKeydown(e));
|
|
152
|
+
|
|
153
|
+
return () => {
|
|
154
|
+
window.removeEventListener('keydown', (e: KeyboardEvent) => handleKeydown(e));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return;
|
|
159
|
+
}, []);
|
|
160
|
+
|
|
161
|
+
if (isDev) {
|
|
162
|
+
return (
|
|
163
|
+
<Button onClick={handlePopulate} type="button" status="primary" className="fixed bottom-4 right-4">
|
|
164
|
+
Populate data
|
|
165
|
+
</Button>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return <></>;
|
|
170
|
+
}
|