tf-checkout-react 1.7.3 → 1.7.5

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 (29) hide show
  1. package/dist/components/common/PhoneNumberField.d.ts +1 -2
  2. package/dist/components/confirmationContainer/index.d.ts +5 -1
  3. package/dist/components/loginModal/SignUpForm.d.ts +10 -0
  4. package/dist/components/loginModal/constants.d.ts +39 -0
  5. package/dist/components/preRegistration/PreRegistrationComplete.d.ts +1 -1
  6. package/dist/components/seatMapContainer/addToCart.d.ts +2 -2
  7. package/dist/components/ticketsContainer/TimeSlotTicketRow.d.ts +19 -0
  8. package/dist/tf-checkout-react.cjs.development.js +817 -85
  9. package/dist/tf-checkout-react.cjs.development.js.map +1 -1
  10. package/dist/tf-checkout-react.cjs.production.min.js +1 -1
  11. package/dist/tf-checkout-react.cjs.production.min.js.map +1 -1
  12. package/dist/tf-checkout-react.esm.js +818 -86
  13. package/dist/tf-checkout-react.esm.js.map +1 -1
  14. package/dist/tf-checkout-styles.css +1 -1
  15. package/package.json +4 -3
  16. package/src/api/publicRequest.ts +1 -0
  17. package/src/components/billing-info-container/index.tsx +1 -1
  18. package/src/components/common/CustomField.tsx +16 -5
  19. package/src/components/common/PhoneNumberField.tsx +7 -10
  20. package/src/components/confirmationContainer/index.tsx +29 -4
  21. package/src/components/loginModal/SignUpForm.tsx +329 -0
  22. package/src/components/loginModal/constants.ts +46 -0
  23. package/src/components/loginModal/index.tsx +94 -26
  24. package/src/components/loginModal/style.css +38 -0
  25. package/src/components/myTicketsContainer/index.tsx +2 -0
  26. package/src/components/preRegistration/PreRegistrationComplete.tsx +3 -1
  27. package/src/components/ticketsContainer/TimeSlotTicketRow.tsx +224 -0
  28. package/src/components/ticketsContainer/TimeSlotsSection.tsx +98 -24
  29. package/src/components/ticketsContainer/index.tsx +1 -1
@@ -2,12 +2,13 @@
2
2
  import { Box, CircularProgress, TextField } from '@mui/material'
3
3
  import { LocalizationProvider, StaticDatePicker as DatePicker } from '@mui/x-date-pickers'
4
4
  import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'
5
- import _isEmpty from 'lodash/isEmpty'
5
+ import _get from 'lodash/get'
6
6
  import _map from 'lodash/map'
7
+ import _sortBy from 'lodash/sortBy'
7
8
  import moment from 'moment-timezone'
8
- import React, { ReactNode, useState } from 'react'
9
+ import React, { ReactNode, useMemo, useState } from 'react'
9
10
 
10
- import { TicketsSection } from './TicketsSection'
11
+ import { TimeSlotTicketRow } from './TimeSlotTicketRow'
11
12
 
12
13
  interface Props {
13
14
  event: any;
@@ -29,6 +30,16 @@ interface Props {
29
30
  isSeatMapAllowed?: boolean;
30
31
  }
31
32
 
33
+ interface TimeSlotOption {
34
+ timeKey: string;
35
+ ticketInstance: any;
36
+ }
37
+
38
+ interface UniqueTicket {
39
+ ticket: any;
40
+ availableTimeSlots: TimeSlotOption[];
41
+ }
42
+
32
43
  const TimeSlotsSection: React.FC<Props> = ({
33
44
  event,
34
45
  availableDates,
@@ -41,14 +52,14 @@ const TimeSlotsSection: React.FC<Props> = ({
41
52
  sortBySoldOut,
42
53
  hideTicketsHeader,
43
54
  ticketsHeaderComponent,
44
- showGroupNameBlock,
45
55
  currencySymbol,
46
- isSeatMapAllowed,
47
56
  }) => {
48
57
  const [loading, setLoading] = useState(false)
58
+ const [selectedTimeSlots, setSelectedTimeSlots] = useState<{ [key: string]: string }>({})
49
59
 
50
60
  const handleDateChange = async (date: string | null) => {
51
61
  setSelectedDate(date)
62
+ setSelectedTimeSlots({}) // Reset time slot selections when date changes
52
63
  if (date) {
53
64
  setLoading(true)
54
65
  try {
@@ -66,6 +77,67 @@ const TimeSlotsSection: React.FC<Props> = ({
66
77
  return !availableDates.includes(formattedDate)
67
78
  }
68
79
 
80
+ // Group tickets by unique ticket type using displayName + price
81
+ const uniqueTickets = useMemo(() => {
82
+ const ticketMap: { [key: string]: UniqueTicket } = {}
83
+
84
+ // Iterate through all time slots
85
+ _map(timeSlotGroups, (tickets, timeKey) => {
86
+ tickets.forEach((ticket: any) => {
87
+ // Use displayName + price as the unique identifier for ticket types
88
+ // This handles cases where multiple ticket types share the same optionName
89
+ const ticketKey = `${ticket.displayName || ticket.name}_${ticket.price}`
90
+
91
+ if (!ticketMap[ticketKey]) {
92
+ ticketMap[ticketKey] = {
93
+ ticket: { ...ticket },
94
+ availableTimeSlots: [],
95
+ }
96
+ }
97
+
98
+ // Store both the time key and the ticket instance for this slot
99
+ if (!ticketMap[ticketKey].availableTimeSlots.find((slot: any) => slot.timeKey === timeKey)) {
100
+ ticketMap[ticketKey].availableTimeSlots.push({
101
+ timeKey,
102
+ ticketInstance: ticket,
103
+ })
104
+ }
105
+ })
106
+ })
107
+
108
+ // Convert to array and sort
109
+ const ticketsArray = Object.values(ticketMap)
110
+ return sortBySoldOut
111
+ ? _sortBy(_sortBy(ticketsArray, t => t.ticket.sortOrder), t => t.ticket.soldOut)
112
+ : _sortBy(ticketsArray, t => t.ticket.sortOrder)
113
+ }, [timeSlotGroups, sortBySoldOut])
114
+
115
+ const handleTimeSlotSelect = (ticketKey: string, timeKey: string, ticketInstance: any) => {
116
+ setSelectedTimeSlots(prev => ({
117
+ ...prev,
118
+ [ticketKey]: timeKey,
119
+ }))
120
+
121
+ // Reset quantity when time slot changes
122
+ if (selectedTickets[ticketInstance.id]) {
123
+ handleTicketSelect(ticketInstance.id, 0)
124
+ }
125
+ }
126
+
127
+ const handleTicketSelectWithTimeSlot = (ticketKey: string, quantity: number, ticketInstance: any) => {
128
+ const timeSlot = selectedTimeSlots[ticketKey]
129
+ if (!timeSlot && quantity > 0) {
130
+ return // Don't allow quantity selection without time slot
131
+ }
132
+
133
+ if (ticketInstance) {
134
+ handleTicketSelect(ticketInstance.id, quantity)
135
+ }
136
+ }
137
+
138
+ const symbol = _get(event, 'currency.symbol')
139
+ const priceSymbol = currencySymbol || symbol
140
+
69
141
  return (
70
142
  <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
71
143
  <LocalizationProvider dateAdapter={AdapterMoment}>
@@ -88,29 +160,31 @@ const TimeSlotsSection: React.FC<Props> = ({
88
160
  width: '100%',
89
161
  display: 'flex',
90
162
  flexDirection: 'column',
91
- gap: 2,
92
163
  }}
93
164
  >
94
- {_map(Object.keys(timeSlotGroups).sort(), timeKey => (
95
- <div key={timeKey} className="time-slot-block">
96
- <div className="time-slot-date">{moment(timeKey).format('hh:mm A')}</div>
97
- <TicketsSection
98
- event={event}
99
- ticketsList={timeSlotGroups[timeKey]}
100
- tableTickets={[]}
165
+ {!hideTicketsHeader && ticketsHeaderComponent}
166
+ {uniqueTickets.map(({ ticket, availableTimeSlots }) => {
167
+ const ticketKey = `${ticket.displayName || ticket.name}_${ticket.price}`
168
+ const isSoldOut =
169
+ ticket.sold_out ||
170
+ !(ticket.displayTicket || ticket.slotGroupId) ||
171
+ ticket.soldOut
172
+
173
+ return (
174
+ <TimeSlotTicketRow
175
+ key={ticketKey}
176
+ ticketKey={ticketKey}
177
+ ticket={ticket}
178
+ availableTimeSlots={availableTimeSlots}
101
179
  selectedTickets={selectedTickets}
102
- handleTicketSelect={handleTicketSelect}
103
- sortBySoldOut={sortBySoldOut}
104
- ticketsHeaderComponent={ticketsHeaderComponent}
105
- tableTicketsHeaderComponent={null}
106
- hideTableTicketsHeader={true}
107
- hideTicketsHeader={hideTicketsHeader || _isEmpty(timeSlotGroups[timeKey])}
108
- showGroupNameBlock={showGroupNameBlock}
109
- currencySymbol={currencySymbol}
110
- isSeatMapAllowed={isSeatMapAllowed}
180
+ selectedTimeSlots={selectedTimeSlots}
181
+ handleTicketSelect={handleTicketSelectWithTimeSlot}
182
+ handleTimeSlotSelect={handleTimeSlotSelect}
183
+ priceSymbol={priceSymbol}
184
+ isSoldOut={isSoldOut}
111
185
  />
112
- </div>
113
- ))}
186
+ )
187
+ })}
114
188
  </Box>
115
189
  )}
116
190
  </Box>
@@ -957,7 +957,7 @@ export const TicketsContainer = ({
957
957
  </div>
958
958
  )}
959
959
  {showLoginModal ? (
960
- <LoginModal onClose={handleOnClose} onLogin={handleOnLogin} />
960
+ <LoginModal onClose={handleOnClose} onLogin={handleOnLogin} showForgotPasswordButton />
961
961
  ) : null}
962
962
  </div>
963
963
  {showPoweredByImage ? <PoweredBy /> : null}