@driveflux/pdf 1.0.15 → 1.1.1

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.
Files changed (106) hide show
  1. package/dist/__mocks__/quotation.d.ts +1 -1
  2. package/dist/__mocks__/quotation.d.ts.map +1 -1
  3. package/dist/__mocks__/quotation.js +1 -2
  4. package/dist/__mocks__/subscription.d.ts +1 -1
  5. package/dist/__mocks__/subscription.d.ts.map +1 -1
  6. package/dist/templates/QuotationPdf/CustomerSubscriptionSection.d.ts.map +1 -1
  7. package/dist/templates/QuotationPdf/CustomerSubscriptionSection.js +2 -10
  8. package/dist/templates/QuotationPdf/index.d.ts +1 -1
  9. package/dist/templates/QuotationPdf/index.d.ts.map +1 -1
  10. package/dist/templates/QuotationPdf/translations.d.ts +0 -1
  11. package/dist/templates/QuotationPdf/translations.d.ts.map +1 -1
  12. package/dist/templates/QuotationPdf/translations.js +44 -47
  13. package/dist/templates/QuotationPdf/utils.d.ts +3 -4
  14. package/dist/templates/QuotationPdf/utils.d.ts.map +1 -1
  15. package/dist/templates/QuotationPdf/utils.js +12 -26
  16. package/dist/templates/SubscriptionAgreement/index.d.ts +1 -1
  17. package/dist/templates/SubscriptionAgreement/index.d.ts.map +1 -1
  18. package/dist/templates/SubscriptionAgreement/translations.d.ts.map +1 -1
  19. package/dist/templates/SubscriptionAgreement/translations.js +269 -269
  20. package/dist/templates/SubscriptionAgreement/utils.d.ts +1 -1
  21. package/dist/templates/SubscriptionAgreement/utils.d.ts.map +1 -1
  22. package/dist/theme/colors.d.ts.map +1 -1
  23. package/dist/theme/colors.js +36 -36
  24. package/dist/utils.d.ts +2 -8
  25. package/dist/utils.d.ts.map +1 -1
  26. package/dist/utils.js +7 -31
  27. package/dist/watch.js +1 -1
  28. package/package.json +23 -20
  29. package/.eslintrc +0 -3
  30. package/.swcrc +0 -14
  31. package/.turbo/turbo-build.log +0 -6
  32. package/CHANGELOG.md +0 -186
  33. package/dist/cjs/__mocks__/quotation.js +0 -70
  34. package/dist/cjs/__mocks__/subscription.js +0 -1079
  35. package/dist/cjs/components/FluxLogo.js +0 -76
  36. package/dist/cjs/components/StandardPage.js +0 -129
  37. package/dist/cjs/debug.js +0 -234
  38. package/dist/cjs/index.js +0 -20
  39. package/dist/cjs/templates/QuotationPdf/CustomerSubscriptionSection.js +0 -155
  40. package/dist/cjs/templates/QuotationPdf/GFV.js +0 -57
  41. package/dist/cjs/templates/QuotationPdf/Header.js +0 -86
  42. package/dist/cjs/templates/QuotationPdf/Pricing.js +0 -430
  43. package/dist/cjs/templates/QuotationPdf/QuotationPdfPage.js +0 -45
  44. package/dist/cjs/templates/QuotationPdf/SectionBoxNew.js +0 -43
  45. package/dist/cjs/templates/QuotationPdf/TermsSection.js +0 -60
  46. package/dist/cjs/templates/QuotationPdf/index.js +0 -208
  47. package/dist/cjs/templates/QuotationPdf/translations.js +0 -106
  48. package/dist/cjs/templates/QuotationPdf/utils.js +0 -108
  49. package/dist/cjs/templates/SubscriptionAgreement/Confirmation.js +0 -95
  50. package/dist/cjs/templates/SubscriptionAgreement/CoverPage.js +0 -110
  51. package/dist/cjs/templates/SubscriptionAgreement/CoverPageSection.js +0 -35
  52. package/dist/cjs/templates/SubscriptionAgreement/Details.js +0 -161
  53. package/dist/cjs/templates/SubscriptionAgreement/Footer.js +0 -68
  54. package/dist/cjs/templates/SubscriptionAgreement/Header.js +0 -61
  55. package/dist/cjs/templates/SubscriptionAgreement/LabelValue.js +0 -39
  56. package/dist/cjs/templates/SubscriptionAgreement/SubscriptionAgreementPage.js +0 -48
  57. package/dist/cjs/templates/SubscriptionAgreement/TermsOfUse.js +0 -72
  58. package/dist/cjs/templates/SubscriptionAgreement/TermsOfUseSubSection.js +0 -108
  59. package/dist/cjs/templates/SubscriptionAgreement/index.js +0 -276
  60. package/dist/cjs/templates/SubscriptionAgreement/translations.js +0 -666
  61. package/dist/cjs/templates/SubscriptionAgreement/utils.js +0 -14
  62. package/dist/cjs/templates/index.js +0 -19
  63. package/dist/cjs/theme/colors.js +0 -147
  64. package/dist/cjs/theme/index.js +0 -18
  65. package/dist/cjs/types.js +0 -4
  66. package/dist/cjs/utils.js +0 -184
  67. package/dist/cjs/watch.js +0 -20
  68. package/index.cjs +0 -1
  69. package/index.d.ts +0 -1
  70. package/src/__mocks__/quotation.ts +0 -63
  71. package/src/__mocks__/subscription.ts +0 -803
  72. package/src/components/FluxLogo.tsx +0 -52
  73. package/src/components/StandardPage.tsx +0 -32
  74. package/src/debug.ts +0 -45
  75. package/src/index.ts +0 -3
  76. package/src/templates/QuotationPdf/CustomerSubscriptionSection.tsx +0 -73
  77. package/src/templates/QuotationPdf/GFV.tsx +0 -29
  78. package/src/templates/QuotationPdf/Header.tsx +0 -31
  79. package/src/templates/QuotationPdf/Pricing.tsx +0 -214
  80. package/src/templates/QuotationPdf/QuotationPdfPage.tsx +0 -25
  81. package/src/templates/QuotationPdf/SectionBoxNew.tsx +0 -20
  82. package/src/templates/QuotationPdf/TermsSection.tsx +0 -28
  83. package/src/templates/QuotationPdf/index.tsx +0 -46
  84. package/src/templates/QuotationPdf/translations.ts +0 -84
  85. package/src/templates/QuotationPdf/utils.ts +0 -59
  86. package/src/templates/SubscriptionAgreement/Confirmation.tsx +0 -49
  87. package/src/templates/SubscriptionAgreement/CoverPage.tsx +0 -52
  88. package/src/templates/SubscriptionAgreement/CoverPageSection.tsx +0 -25
  89. package/src/templates/SubscriptionAgreement/Details.tsx +0 -127
  90. package/src/templates/SubscriptionAgreement/Footer.tsx +0 -37
  91. package/src/templates/SubscriptionAgreement/Header.tsx +0 -37
  92. package/src/templates/SubscriptionAgreement/LabelValue.tsx +0 -19
  93. package/src/templates/SubscriptionAgreement/SubscriptionAgreementPage.tsx +0 -24
  94. package/src/templates/SubscriptionAgreement/TermsOfUse.tsx +0 -30
  95. package/src/templates/SubscriptionAgreement/TermsOfUseSubSection.tsx +0 -44
  96. package/src/templates/SubscriptionAgreement/index.tsx +0 -66
  97. package/src/templates/SubscriptionAgreement/translations.ts +0 -664
  98. package/src/templates/SubscriptionAgreement/utils.ts +0 -7
  99. package/src/templates/index.ts +0 -2
  100. package/src/theme/colors.ts +0 -180
  101. package/src/theme/index.ts +0 -1
  102. package/src/types.ts +0 -1
  103. package/src/utils.ts +0 -27
  104. package/src/watch.ts +0 -16
  105. package/tsconfig.json +0 -13
  106. package/tsconfig.tsbuildinfo +0 -1
@@ -1,52 +0,0 @@
1
- import { Defs, G, Path, Rect, Svg } from '@react-pdf/renderer'
2
-
3
- const FluxLogo = () => {
4
- return (
5
- <Svg width="92" height="29" viewBox="0 0 92 29" fill="none">
6
- <G clipPath="url(#clip0_664_102105)">
7
- <Path
8
- d="M23.6621 6.12305H35.6903V8.00999H25.5568V13.5529H33.805V15.434H25.5568V22.8638H23.6715L23.6621 6.12305Z"
9
- fill="black"
10
- />
11
- <Path d="M40.9981 6.12305H42.8834V20.9827H52.3039V22.8697H40.9922L40.9981 6.12305Z" fill="black" />
12
- <Path
13
- d="M57.6172 15.6002V6.12305H59.5025V15.4811C59.5025 19.0946 61.4149 21.129 64.6187 21.129C67.7035 21.129 69.6642 19.2621 69.6642 15.6002V6.12305H71.5495V15.4552C71.5495 20.3376 68.751 22.8744 64.5669 22.8744C60.4381 22.8756 57.6172 20.3388 57.6172 15.6002Z"
14
- fill="black"
15
- />
16
- <Path
17
- d="M83.2965 14.3324L77.1033 6.12305H79.3338L84.4736 12.9632L89.5663 6.12305H91.7674L85.5742 14.3077L92.0054 22.8756H89.7525L84.4006 15.6722L79.0451 22.8756H76.8594L83.2965 14.3324Z"
18
- fill="black"
19
- />
20
- <Path
21
- opacity="0.3"
22
- d="M3.05934 17.5614C2.45475 17.5598 1.86415 17.3792 1.36192 17.0423C0.859683 16.7054 0.468271 16.2273 0.23697 15.6682C0.00566877 15.1091 -0.0551799 14.494 0.0620863 13.9004C0.179353 13.3068 0.469491 12.7611 0.895964 12.3322L12.3256 0.892604C12.909 0.364801 13.6728 0.0817665 14.459 0.102098C15.2452 0.12243 15.9934 0.444573 16.5488 1.00183C17.1042 1.55908 17.4243 2.30877 17.4426 3.09567C17.461 3.88257 17.1764 4.64641 16.6476 5.22904L5.218 16.6686C4.93441 16.9521 4.59781 17.1768 4.22742 17.33C3.85703 17.4832 3.46011 17.5618 3.05934 17.5614Z"
23
- fill="#50C8E8"
24
- />
25
- <Path
26
- opacity="0.3"
27
- d="M8.77458 23.28C8.16964 23.2788 7.57859 23.0985 7.07593 22.7616C6.57326 22.4248 6.18149 21.9465 5.94999 21.3871C5.7185 20.8277 5.65764 20.2123 5.7751 19.6183C5.89256 19.0244 6.18308 18.4786 6.61002 18.0496L12.3213 12.3334C12.6004 12.027 12.9387 11.7804 13.3158 11.6086C13.6928 11.4368 14.1008 11.3433 14.5149 11.3338C14.9291 11.3243 15.3409 11.399 15.7254 11.5533C16.1099 11.7076 16.4592 11.9384 16.752 12.2317C17.0449 12.525 17.2753 12.8746 17.4293 13.2596C17.5832 13.6445 17.6576 14.0567 17.6479 14.4712C17.6382 14.8858 17.5446 15.294 17.3727 15.6713C17.2008 16.0486 16.9543 16.3871 16.648 16.6663L10.9368 22.3837C10.653 22.6681 10.3159 22.8936 9.94489 23.0474C9.57386 23.2013 9.17617 23.2803 8.77458 23.28Z"
28
- fill="#50C8E8"
29
- />
30
- <Path
31
- d="M14.4866 29.0001C16.176 29.0001 17.5455 27.6294 17.5455 25.9385C17.5455 24.2477 16.176 22.877 14.4866 22.877C12.7972 22.877 11.4277 24.2477 11.4277 25.9385C11.4277 27.6294 12.7972 29.0001 14.4866 29.0001Z"
32
- fill="#50C8E8"
33
- />
34
- <Path
35
- d="M14.4866 6.12314C16.176 6.12314 17.5455 4.75243 17.5455 3.06157C17.5455 1.37071 16.176 0 14.4866 0C12.7972 0 11.4277 1.37071 11.4277 3.06157C11.4277 4.75243 12.7972 6.12314 14.4866 6.12314Z"
36
- fill="#50C8E8"
37
- />
38
- <Path
39
- d="M14.4866 17.5616C16.176 17.5616 17.5455 16.1909 17.5455 14.5C17.5455 12.8092 16.176 11.4385 14.4866 11.4385C12.7972 11.4385 11.4277 12.8092 11.4277 14.5C11.4277 16.1909 12.7972 17.5616 14.4866 17.5616Z"
40
- fill="#50C8E8"
41
- />
42
- </G>
43
- <Defs>
44
- <clipPath id="clip0_664_102105">
45
- <Rect width="92" height="29" fill="white" />
46
- </clipPath>
47
- </Defs>
48
- </Svg>
49
- )
50
- }
51
-
52
- export default FluxLogo
@@ -1,32 +0,0 @@
1
- import { Font, Page, PageProps } from '@react-pdf/renderer'
2
- import React, { PropsWithChildren } from 'react'
3
-
4
- type Props = PageProps & {}
5
-
6
- Font.register({
7
- family: 'Figtree',
8
- fonts: [
9
- {
10
- src: 'https://fonts.gstatic.com/s/figtree/v5/_Xmz-HUzqDCFdgfMsYiV_F7wfS-Bs_chQF5ewkEU4HTy.ttf',
11
- fontWeight: 'normal'
12
- },
13
- {
14
- src: 'https://fonts.gstatic.com/s/figtree/v5/_Xmz-HUzqDCFdgfMsYiV_F7wfS-Bs_eYR15ewkEU4HTy.ttf',
15
- fontWeight: 'bold'
16
- }
17
- ]
18
- })
19
- Font.register({
20
- family: 'Allura',
21
- src: 'https://fonts.gstatic.com/s/allura/v21/9oRPNYsQpS4zjuAPjAIXPtrrGA.ttf'
22
- })
23
-
24
- const StandardDocument: React.FC<PropsWithChildren<Props>> = ({ children, style, ...props }) => {
25
- return (
26
- <Page style={{ fontFamily: 'Figtree', fontStyle: 'normal', ...style }} {...props}>
27
- {children}
28
- </Page>
29
- )
30
- }
31
-
32
- export default StandardDocument
package/src/debug.ts DELETED
@@ -1,45 +0,0 @@
1
- import { loadAllEnv } from '@driveflux/env'
2
- import { quotation } from './__mocks__/quotation.js'
3
- import { subscription } from './__mocks__/subscription.js'
4
- import { generateSubscriptionAgreementPdf } from './templates/SubscriptionAgreement/index.js'
5
- import { generateQuotationPdf } from './templates/index.js'
6
-
7
- const debugSubscriptionAgreement = async () => {
8
- if (!subscription) {
9
- console.error('no such subscription')
10
- return
11
- }
12
-
13
- await generateSubscriptionAgreementPdf({ subscription }, `${process.cwd()}/output/subscription-agreement.pdf`)
14
- }
15
-
16
- const debugQuotation = async () => {
17
- if (!quotation) {
18
- console.error('no such quotation')
19
- return
20
- }
21
-
22
- await generateQuotationPdf({ quotation }, `${process.cwd()}/output/quotation.pdf`)
23
- }
24
-
25
- //! put all the debugging functions here
26
- const debugCases: Promise<any>[] = [debugSubscriptionAgreement(), debugQuotation()]
27
-
28
- const debug = async () => {
29
- loadAllEnv()
30
-
31
- const results = await Promise.allSettled(debugCases)
32
-
33
- if (results.some((res) => res.status === 'rejected')) {
34
- results.forEach((res, i) => {
35
- if (res.status === 'rejected') {
36
- console.error(`debug no ${i + 1} error:`, res.reason)
37
- }
38
- })
39
- return
40
- }
41
-
42
- console.log('Generated all PDFs successfully!')
43
- console.log(`You can view them in the 'output' folder!`)
44
- }
45
- debug()
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './templates/index.js'
2
- export * from './types.js'
3
- export * from './utils.js'
@@ -1,73 +0,0 @@
1
- import { Quotation } from '@driveflux/db'
2
- import { Address } from '@driveflux/db/types/index.js'
3
- import { Text, View } from '@react-pdf/renderer'
4
- import { FC } from 'react'
5
- import { colors } from '../../theme/colors.js'
6
- import SectionBoxNew from './SectionBoxNew.js'
7
- import { QuotationPdfTranslation } from './translations.js'
8
- import { formatAddress, getFullMileagePackageTranslation, getSimplifiedPlanTranslation } from './utils.js'
9
-
10
- type Props = {
11
- quotation: Quotation
12
- t: QuotationPdfTranslation
13
- }
14
-
15
- const CustomerSubscriptionSection: FC<Props> = ({ quotation, t }) => {
16
- const displayContent = (label: string, value: string, labelColor = colors.black, valueColor = colors.primary3) => (
17
- <View style={{ gap: 4 }}>
18
- <Text style={{ color: labelColor, letterSpacing: 1 }}>{label}</Text>
19
- <Text style={{ color: valueColor, letterSpacing: 1 }}>{value}</Text>
20
- </View>
21
- )
22
-
23
- return (
24
- <View>
25
- <SectionBoxNew
26
- topContent={
27
- <>
28
- <Text style={{ textTransform: 'uppercase', fontSize: 12, fontWeight: 'bold' }}>{t.customer.title}</Text>
29
- <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
30
- {displayContent(t.customer.name, quotation.customerName)}
31
- {quotation.customer.email && displayContent(t.customer.email, quotation.customer.email)}
32
- </View>
33
- {quotation.customer.address &&
34
- displayContent(t.customer.address, formatAddress(quotation.customer.address as Address))}
35
- </>
36
- }
37
- bottomContent={
38
- <>
39
- <Text style={{ textTransform: 'uppercase', fontSize: 12, fontWeight: 'bold' }}>{t.subscription.title}</Text>
40
- <View style={{ flexDirection: 'row', justifyContent: 'space-between', gap: 4 }}>
41
- {displayContent(t.subscription.vehicleName, quotation.vehicleName)}
42
- <View style={{ justifyContent: 'space-between', flexDirection: 'row', gap: 16 }}>
43
- {displayContent(t.subscription.plan, getSimplifiedPlanTranslation(quotation.plan))}
44
- {displayContent(
45
- t.subscription.mileagePackage,
46
- getFullMileagePackageTranslation(quotation.mileagePackage)
47
- )}
48
- </View>
49
- </View>
50
- <View style={{ rowGap: 8 }}>
51
- <Text style={{ color: colors.primary3, fontWeight: 'bold', letterSpacing: 1 }}>
52
- {t.subIncludes.title}
53
- </Text>
54
- {t.subIncludes.content.map((line, i) => (
55
- <View key={i} style={{ flexDirection: 'row', alignItems: 'flex-start', rowGap: 8 }}>
56
- <Text style={{ marginRight: 4 }}>•</Text>
57
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>{line}</Text>
58
- </View>
59
- ))}
60
- {quotation.mileagePackage !== 'unlimited' && (
61
- <Text style={{ fontSize: '9px', color: colors.primary3, letterSpacing: 1 }}>
62
- {t.subIncludes.excessMileage(quotation.fees.excessMileageFee || 0)}
63
- </Text>
64
- )}
65
- </View>
66
- </>
67
- }
68
- />
69
- </View>
70
- )
71
- }
72
-
73
- export default CustomerSubscriptionSection
@@ -1,29 +0,0 @@
1
- import { Quotation } from '@driveflux/db'
2
- import { formatMoney } from '@driveflux/format-money'
3
- import { Text, View } from '@react-pdf/renderer'
4
- import { FC } from 'react'
5
- import { colors } from '../../theme/colors.js'
6
- import { QuotationPdfTranslation } from './translations'
7
-
8
- type Props = {
9
- quotation: Quotation
10
- t?: QuotationPdfTranslation['pricing']
11
- }
12
-
13
- const GFV: FC<Props> = ({ quotation, t }) => {
14
- if (!quotation.fees.gfv) return
15
-
16
- return (
17
- <View style={{ border: `1px solid ${colors.primary2}`, padding: 16, rowGap: 16 }}>
18
- <Text style={{ color: colors.primary3, fontWeight: 'bold', letterSpacing: 1, textTransform: 'uppercase' }}>
19
- {t?.fees.gfv.title}
20
- </Text>
21
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>
22
- You have the option to purchase this vehicle with GFV amount of
23
- <Text style={{ fontWeight: 'bold' }}> {formatMoney(quotation.fees.gfv)} </Text>at the end of your subscription.
24
- </Text>
25
- </View>
26
- )
27
- }
28
-
29
- export default GFV
@@ -1,31 +0,0 @@
1
- import { Link, Text, View } from '@react-pdf/renderer'
2
- import { FC } from 'react'
3
- import FluxLogo from '../../components/FluxLogo.js'
4
- import { colors } from '../../theme/colors.js'
5
-
6
- type Props = {
7
- tTitle: string
8
- quotationId: string
9
- quotationDate: string
10
- }
11
- const Header: FC<Props> = ({ tTitle, quotationId, quotationDate }) => {
12
- return (
13
- <View style={{ gap: 24 }}>
14
- <Link src="https://driveflux.com">
15
- <FluxLogo />
16
- </Link>
17
- <View style={{ gap: 4 }}>
18
- <Text style={{ fontWeight: 'bold', textTransform: 'uppercase', fontSize: 18 }}>{tTitle}</Text>
19
- <View style={{ justifyContent: 'space-between', flexDirection: 'row' }}>
20
- <Text style={{ color: colors.primary3, fontSize: 10 }}>{quotationId}</Text>
21
- <View style={{ gap: 8, flexDirection: 'row' }}>
22
- <Text style={{ fontSize: 10, color: colors.black }}>Date</Text>
23
- <Text style={{ color: colors.primary3, fontSize: 10 }}>{quotationDate}</Text>
24
- </View>
25
- </View>
26
- </View>
27
- </View>
28
- )
29
- }
30
-
31
- export default Header
@@ -1,214 +0,0 @@
1
- import { Quotation } from '@driveflux/db'
2
- import { formatMoney } from '@driveflux/format-money'
3
- import { Text, View } from '@react-pdf/renderer'
4
- import { FC } from 'react'
5
- import { colors } from '../../theme/colors.js'
6
- import SectionBoxNew from './SectionBoxNew.js'
7
- import { QuotationPdfTranslation } from './translations.js'
8
-
9
- type Props = {
10
- quotation: Quotation
11
- t?: QuotationPdfTranslation['pricing']
12
- }
13
-
14
- const Pricing: FC<Props> = ({ quotation, t }) => {
15
- const { startFee, reservationFee, deposit, subscriptionFee, extraCharges, couponCode, couponType, discountAmount } =
16
- quotation.fees
17
-
18
- let totalUpfrontFee = startFee + (reservationFee || 0) + deposit
19
- let totalMonthlyFee = subscriptionFee
20
-
21
- extraCharges.forEach((charge) => {
22
- if (charge.type === 'upfront') {
23
- totalUpfrontFee += charge.amount
24
- } else if (charge.type === 'monthly') {
25
- totalMonthlyFee += charge.amount
26
- }
27
- })
28
-
29
- if (couponCode && couponType === 'upfront') {
30
- totalUpfrontFee -= discountAmount || 0
31
- }
32
-
33
- if (couponCode && couponType === 'monthly') {
34
- totalMonthlyFee -= discountAmount || 0
35
- }
36
-
37
- const getFeeValue = (key: string) => {
38
- switch (key) {
39
- case 'startFee':
40
- return startFee
41
- case 'reservationFee':
42
- return reservationFee
43
- case 'deposit':
44
- return deposit
45
- case 'subscriptionFee':
46
- return subscriptionFee
47
- default:
48
- return null
49
- }
50
- }
51
-
52
- return (
53
- <View>
54
- <SectionBoxNew
55
- topContent={
56
- <>
57
- <Text style={{ textTransform: 'uppercase', fontSize: 12, fontWeight: 'bold' }}>{t?.title}</Text>
58
- {/* upfront */}
59
- <Text style={{ fontWeight: 'bold', color: colors.black, letterSpacing: 1 }}>{t?.fees.upfront.title}</Text>
60
- {t?.fees.upfront.content.map((fee) => {
61
- const feeValue = getFeeValue(fee.key)?.toFixed(2)
62
- if (feeValue === '0.00') {
63
- return null
64
- }
65
- return (
66
- <View key={fee.key} style={{ justifyContent: 'space-between', flexDirection: 'row', rowGap: 8 }}>
67
- <Text style={{ paddingRight: 4, letterSpacing: 1, color: colors.primary3 }}>{fee.title}</Text>
68
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>{feeValue !== null ? feeValue : ''}</Text>
69
- </View>
70
- )
71
- })}
72
- {/* extra charge */}
73
- {quotation.fees.extraCharges.length > 0 && (
74
- <>
75
- {quotation.fees.extraCharges
76
- .filter((charge) => charge.amount > 0)
77
- .filter((charge) => charge.type === 'upfront')
78
- .map((charge, i) => (
79
- <View key={i} style={{ justifyContent: 'space-between', flexDirection: 'row', rowGap: 8 }}>
80
- <Text style={{ paddingRight: 4, letterSpacing: 1, color: colors.primary3 }}>
81
- {t?.fees.extraCharge} - {charge.description}
82
- </Text>
83
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>{charge.amount.toFixed(2)}</Text>
84
- </View>
85
- ))}
86
- </>
87
- )}
88
- {quotation.fees.couponCode !== null && quotation.fees.couponType === 'upfront' && (
89
- <>
90
- <View style={{ justifyContent: 'space-between', flexDirection: 'row', rowGap: 8 }}>
91
- <Text style={{ paddingRight: 4, letterSpacing: 1, color: colors.primary3 }}>
92
- {t?.fees.promo} - {quotation.fees.couponCode}
93
- </Text>
94
- <Text style={{ color: colors.accent4, letterSpacing: 1 }}>
95
- {quotation.fees.discountAmount?.toFixed(2)}
96
- </Text>
97
- </View>
98
- </>
99
- )}
100
- <View
101
- style={{
102
- backgroundColor: colors.primary1,
103
- borderTop: `1px solid ${colors.primary1}`,
104
- justifyContent: 'space-between',
105
- flexDirection: 'row',
106
- padding: 4
107
- }}
108
- >
109
- <Text style={{ letterSpacing: 1, paddingRight: 4 }}>Total</Text>
110
- <Text style={{ letterSpacing: 1 }}>{formatMoney(totalUpfrontFee)}</Text>
111
- </View>
112
-
113
- <View style={{ borderBottom: `1px solid ${colors.primary2}` }}></View>
114
-
115
- {/* monthly */}
116
- <Text style={{ fontWeight: 'bold', color: colors.black, letterSpacing: 1 }}>{t?.fees.monthly.title}</Text>
117
- {t?.fees.monthly.content.map((fee) => {
118
- const feeValue = getFeeValue(fee.key)?.toFixed(2)
119
-
120
- return (
121
- <View key={fee.key} style={{ justifyContent: 'space-between', flexDirection: 'row', rowGap: 8 }}>
122
- <Text style={{ paddingRight: 4, letterSpacing: 1, color: colors.primary3 }}>{fee.title}</Text>
123
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>{feeValue !== null ? feeValue : ''}</Text>
124
- </View>
125
- )
126
- })}
127
-
128
- {/* extra charges monthly*/}
129
- {quotation.fees.extraCharges.length > 0 && (
130
- <>
131
- {quotation.fees.extraCharges
132
- .filter((charge) => charge.type === 'monthly')
133
- .map((charge, i) => (
134
- <View key={i} style={{ justifyContent: 'space-between', flexDirection: 'row', rowGap: 8 }}>
135
- <Text style={{ paddingRight: 4, letterSpacing: 1, color: colors.primary3 }}>
136
- {t?.fees.extraCharge} - {charge.description}
137
- </Text>
138
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>{charge.amount.toFixed(2)}</Text>
139
- </View>
140
- ))}
141
- </>
142
- )}
143
-
144
- {/* promo monthly */}
145
- {quotation.fees.couponCode !== null && quotation.fees.couponType === 'monthly' && (
146
- <>
147
- <View style={{ justifyContent: 'space-between', flexDirection: 'row', rowGap: 8 }}>
148
- <Text style={{ paddingRight: 4, letterSpacing: 1, color: colors.primary3 }}>
149
- {t?.fees.promo} - {quotation.fees.couponCode}
150
- </Text>
151
- <Text style={{ color: colors.accent4, letterSpacing: 1 }}>
152
- {quotation.fees.discountAmount?.toFixed(2)}
153
- </Text>
154
- </View>
155
- </>
156
- )}
157
-
158
- <View
159
- style={{
160
- backgroundColor: colors.primary1,
161
- borderTop: `1px solid ${colors.primary1}`,
162
- justifyContent: 'space-between',
163
- flexDirection: 'row',
164
- padding: 4
165
- }}
166
- >
167
- <Text style={{ letterSpacing: 1, paddingRight: 4 }}>Total</Text>
168
- <Text style={{ letterSpacing: 1 }}>{formatMoney(totalMonthlyFee)}</Text>
169
- </View>
170
- </>
171
- }
172
- bottomContent={
173
- <>
174
- <View style={{ rowGap: 16 }}>
175
- <Text style={{ textTransform: 'uppercase', fontSize: 12, fontWeight: 'bold', letterSpacing: 1 }}>
176
- {t?.fees.dueToday.title}
177
- </Text>
178
- <Text style={{ color: colors.primary3, letterSpacing: 1 }}>{t?.fees.dueToday.description}</Text>
179
- <View style={{ justifyContent: 'space-between', flexDirection: 'row' }}>
180
- <Text style={{ letterSpacing: 1, color: colors.primary3 }}> {t?.fees.dueToday.subTotal}</Text>
181
- <Text style={{ letterSpacing: 1, color: colors.primary3 }}>
182
- {quotation.fees.amountBeforeTax.toFixed(2)}
183
- </Text>
184
- </View>
185
- <View style={{ justifyContent: 'space-between', flexDirection: 'row' }}>
186
- <Text style={{ letterSpacing: 1, color: colors.primary3 }}> {t?.fees.dueToday.serviceFee}</Text>
187
- <Text style={{ letterSpacing: 1, color: colors.primary3 }}>{quotation.fees.taxAmount.toFixed(2)}</Text>
188
- </View>
189
-
190
- <View
191
- style={{
192
- backgroundColor: colors.primary1,
193
- borderTop: `1px solid ${colors.primary1}`,
194
- justifyContent: 'space-between',
195
- flexDirection: 'row',
196
- padding: 4
197
- }}
198
- >
199
- <Text style={{ letterSpacing: 1, paddingRight: 4, fontWeight: 'bold' }}>
200
- {t?.fees.dueToday.grandTotal}
201
- </Text>
202
- <Text style={{ letterSpacing: 1, fontWeight: 'bold' }}>
203
- {formatMoney(quotation.fees.amountAfterTax)}
204
- </Text>
205
- </View>
206
- </View>
207
- </>
208
- }
209
- />
210
- </View>
211
- )
212
- }
213
-
214
- export default Pricing
@@ -1,25 +0,0 @@
1
- import { Quotation } from '@driveflux/db'
2
- import { View } from '@react-pdf/renderer'
3
- import { format } from 'date-fns'
4
- import { FC, PropsWithChildren } from 'react'
5
- import StandardPage from '../../components/StandardPage.js'
6
- import Header from './Header.js'
7
-
8
- type Props = {
9
- quotation: Quotation
10
- }
11
-
12
- const QuotationPdfPage: FC<PropsWithChildren<Props>> = ({ quotation, children }) => {
13
- return (
14
- <StandardPage style={{ padding: 40, fontSize: 10, gap: 16 }}>
15
- <Header
16
- tTitle={'Quotation'}
17
- quotationId={quotation.id}
18
- quotationDate={format(quotation.createdAt, 'dd-MM-yyyy')}
19
- />
20
- <View style={{ flex: 1, rowGap: 24 }}>{children}</View>
21
- </StandardPage>
22
- )
23
- }
24
-
25
- export default QuotationPdfPage
@@ -1,20 +0,0 @@
1
- import { View } from '@react-pdf/renderer'
2
- import { FC, ReactNode } from 'react'
3
- import { colors } from '../../theme/colors.js'
4
-
5
- type Props = {
6
- topContent: ReactNode
7
- bottomContent: ReactNode
8
- }
9
-
10
- const SectionBoxNew: FC<Props> = ({ topContent, bottomContent }) => {
11
- return (
12
- <View style={{ border: `1px solid ${colors.primary2}` }}>
13
- <View style={{ padding: 16, rowGap: 16 }}>{topContent}</View>
14
- <View style={{ borderBottom: `1px solid ${colors.primary2}` }} />
15
- <View style={{ padding: 16, rowGap: 16 }}>{bottomContent}</View>
16
- </View>
17
- )
18
- }
19
-
20
- export default SectionBoxNew
@@ -1,28 +0,0 @@
1
- import { Text, View } from '@react-pdf/renderer'
2
- import { FC } from 'react'
3
- import { colors } from '../../theme/colors.js'
4
- import { QuotationPdfTranslation } from './translations.js'
5
-
6
- type Props = {
7
- t: QuotationPdfTranslation['terms']
8
- }
9
-
10
- const TermsSection: FC<Props> = ({ t }) => {
11
- return (
12
- <View style={{ gap: 16 }}>
13
- <Text style={{ fontWeight: 'bold', color: colors.black, letterSpacing: 1, textTransform: 'uppercase' }}>
14
- {t?.title}
15
- </Text>
16
- <View>
17
- {t.content.map((line, i) => (
18
- <View key={i} style={{ flexDirection: 'row', alignItems: 'flex-start' }}>
19
- <Text style={{ marginRight: 4, fontSize: 8 }}>•</Text>
20
- <Text style={{ color: colors.primary3, letterSpacing: 1, fontSize: 8 }}>{line}</Text>
21
- </View>
22
- ))}
23
- </View>
24
- </View>
25
- )
26
- }
27
-
28
- export default TermsSection
@@ -1,46 +0,0 @@
1
- import { Quotation } from '@driveflux/db'
2
- import { Document } from '@react-pdf/renderer'
3
- import { FC, useMemo } from 'react'
4
- import { PdfTemplatesSupportedLocales } from '../../types.js'
5
- import { toPdf } from '../../utils.js'
6
- import CustomerSubscriptionSection from './CustomerSubscriptionSection.js'
7
- import GFV from './GFV.js'
8
- import Pricing from './Pricing.js'
9
- import QuotationPdfPage from './QuotationPdfPage.js'
10
- import TermsSection from './TermsSection.js'
11
- import { useTranslations } from './translations.js'
12
-
13
- type Props = {
14
- locale?: PdfTemplatesSupportedLocales
15
- quotation: Quotation
16
- }
17
-
18
- type Options = {
19
- locale?: PdfTemplatesSupportedLocales
20
- quotation: Quotation
21
- }
22
-
23
- export const generateQuotationPdf = async ({ locale = 'en', quotation }: Options, fileName?: string) => {
24
- return await toPdf(<QuotationPDF locale={locale} quotation={quotation} />, fileName)
25
- }
26
-
27
- const QuotationPDF: FC<Props> = ({ locale = 'en', quotation }) => {
28
- const pageProps = useMemo(() => {
29
- return {
30
- t: useTranslations(locale),
31
- quotation: quotation
32
- }
33
- }, [])
34
- const { t } = pageProps
35
-
36
- return (
37
- <Document language={locale}>
38
- <QuotationPdfPage quotation={quotation}>
39
- <CustomerSubscriptionSection quotation={quotation} t={t} />
40
- <Pricing quotation={quotation} t={t.pricing} />
41
- {quotation.fees.gfv && <GFV quotation={quotation} t={t.pricing} />}
42
- <TermsSection t={t.terms} />
43
- </QuotationPdfPage>
44
- </Document>
45
- )
46
- }