/* eslint-disable @typescript-eslint/no-explicit-any */ import './style.css' import { Backdrop, CircularProgress, ThemeOptions } from '@mui/material' import Paper from '@mui/material/Paper' import { createTheme, ThemeProvider } from '@mui/material/styles' import Table from '@mui/material/Table' import TableBody from '@mui/material/TableBody' import TableCell from '@mui/material/TableCell' import TableContainer from '@mui/material/TableContainer' import TableHead from '@mui/material/TableHead' import TableRow from '@mui/material/TableRow' import { CSSProperties } from '@mui/styles' import _find from 'lodash/find' import _get from 'lodash/get' import _has from 'lodash/has' import _identity from 'lodash/identity' import _isEmpty from 'lodash/isEmpty' import _map from 'lodash/map' import moment from 'moment-timezone' import React, { useEffect, useMemo, useState } from 'react' import SVG from 'react-inlinesvg' import { getOrderDetails, removeFromResale, resaleTicket, updateOrderCustomFields, updateTicketHoldersCustomFields, } from '../../api' import EditSvg from '../../assets/images/edit.svg' import { isBrowser } from '../../utils' import ConfirmModal from '../confirmModal' import { InitialValuesTypes, TicketResaleModal } from '../ticketResaleModal' import { CustomFieldsForm } from './CustomFieldsForm' import TicketsTable, { IActionColumns, ITicketTypes } from './ticketsTable' import { isFieldUpdatable, renderCustomFieldValue } from './utils' interface TicketTypes { currency: string; discount: string; name: string; price: string; quantity: string; total: string; groupName: string; guests_count: string; deposit_paid: string; remaining: string; } interface OrderDetailsTypes { columns: Array<{ label: string }>; onGetOrdersSuccess: (res: any) => void; onGetOrdersError: (err: any) => void; onReturnButtonClick: (data: any) => void; onRemoveFromResaleSuccess: () => void; onRemoveFromResaleError: (err: any) => void; onResaleTicketSuccess: () => void; onResaleTicketError: (err: any) => void; onUpdateOrderCustomFieldsSuccess: (val: any) => void; onUpdateOrderCustomFieldsError: (err: any) => void; onUpdateTicketHolderCustomFieldsSuccess: (val: any) => void; onUpdateTicketHolderCustomFieldsError: (err: any) => void; personalLinkIcon?: string; displayColumnNameInRow?: boolean; canSellTicket?: boolean; themeOptions?: ThemeOptions & { input?: CSSProperties; checkbox?: CSSProperties; }; ticketsTableColumns?: Array<{ id?: string | number; key: keyof ITicketTypes & keyof IActionColumns; label: string | number | null | undefined; }>; ordersPath?: string; orderId?: string | number; referralTitle?: string; itemsTitle?: string; ticketsTitle?: string; displayLoading?: boolean; onDataLoaded?: (data: any) => void; } export interface CustomFieldOption { id: string; name: string; value: string; order: string; } export interface CustomFieldTypes { description: string; enabled: string; id: string; label: string; name: string; orderId: string; required: boolean; settings: { showOnMyTickets: boolean; allowUpdate: boolean; className: string; }; type: string; value: string | Array; ticketHash?: string; options?: CustomFieldOption[]; } const getTotal = (data: any) => { if (data?.total && data?.tickets && data.tickets[0]?.currency) return data.tickets[0].currency + data.total if (!data?.total || !_has(data, 'items.ticket_types.length')) return '' return data.items.ticket_types[0].currency + data.total } export const OrderDetailsContainer = ({ columns = [], onGetOrdersSuccess = _identity, onGetOrdersError = _identity, onRemoveFromResaleSuccess = _identity, onRemoveFromResaleError = _identity, onResaleTicketSuccess = _identity, onResaleTicketError = _identity, onUpdateOrderCustomFieldsSuccess = _identity, onUpdateOrderCustomFieldsError = _identity, onUpdateTicketHolderCustomFieldsSuccess = _identity, onUpdateTicketHolderCustomFieldsError = _identity, onReturnButtonClick, personalLinkIcon = '', displayColumnNameInRow = false, canSellTicket = true, ticketsTableColumns, ordersPath, orderId: pOrderId, referralTitle = '', itemsTitle = '', ticketsTitle = 'Your Tickets', themeOptions, displayLoading = true, onDataLoaded = _identity, }: OrderDetailsTypes) => { const [data, setData] = useState({}) const [removeFromResaleLoading, setRemoveFromResaleLoading] = useState(false) const [resaleTicketLoading, setResaleTicketLoading] = useState(false) const [showResaleModal, setShowResaleModal] = useState(false) const [showRemoveResaleModal, setShowRemoveResaleModal] = useState(false) const [activeTicket, setActiveTicket] = useState(null) const [showOrderCustomFieldsSection, setShowOrderCustomFieldsSection] = useState(false) const [isLoading, setIsLoading] = useState(false) const isTable = _get(data, 'tickets[0].is_table', false) const columnsProps = isTable ? [ { label: 'Items' }, { label: 'Price' }, { label: 'Guests count' }, { label: 'Deposit paid' }, { label: 'Remaining' }, ] : columns const ticketHoldersCustomFields = _get(data, 'ticket_data_capture', []) const orderCustomFields = _get(data, 'data_capture', []) const [orderUpdatableCustomFields, orderNotUpdatableCustomFields] = useMemo(() => { const allowedFields: CustomFieldTypes[] = [] const notAllowedFields: CustomFieldTypes[] = [] orderCustomFields.forEach((field: CustomFieldTypes) => { if (isFieldUpdatable(field)) { allowedFields.push(field) } else { notAllowedFields.push(field) } }) return [allowedFields, notAllowedFields] }, [orderCustomFields]) const orderEditableFieldsFormInitialValues = useMemo(() => { const initialValues = orderUpdatableCustomFields.map((field: CustomFieldTypes) => [ field.name, field.type === 'checkbox' ? Boolean(field.value) : field.value || '', ]) return Object.fromEntries(initialValues) }, [orderUpdatableCustomFields]) let orderId = String(pOrderId) || '' if (isBrowser && !pOrderId) { const params: URLSearchParams = new URL(`${window.location}`).searchParams orderId = params.get('o') || '' } let orderSummery = `ID ${data.id}, placed` if (data.date && data.timezone) { const date = moment.tz(data.date, data.timezone).format('dddd, DD MMMM YYYY') orderSummery += ` ${date}` } useEffect(() => { (async () => { try { let orderId = pOrderId || '' if (isBrowser && !pOrderId) { const params: URLSearchParams = new URL(`${window.location}`).searchParams orderId = params.get('o') || '' } setIsLoading(true) const response = await getOrderDetails(String(orderId)) onGetOrdersSuccess(response) const data = _get(response, 'data.attributes') setData(data) setIsLoading(false) onDataLoaded(data) } catch (error) { onGetOrdersError(error) setIsLoading(false) } })() }, [onGetOrdersError, onGetOrdersSuccess, onDataLoaded, pOrderId]) const handleSellTicket = (ticket: ITicketTypes) => { const ticketTypesArr = data.items.ticket_types const sellTicketType = _find( ticketTypesArr, ticketType => ticketType.hash === ticket.ticket_type_hash ) setActiveTicket({ ...ticket, ticket_type_is_active: sellTicketType?.active, }) setShowResaleModal(true) } const handleOnClose = () => { setShowResaleModal(false) setActiveTicket(null) } const handleOnSubmit = async (values: InitialValuesTypes) => { if (resaleTicketLoading) { return } try { setResaleTicketLoading(true) const { to, first_name, last_name, email, confirm_email, confirm } = values const formData = new FormData() formData.append('to', to) formData.append('first_name', first_name) formData.append('last_name', last_name) formData.append('email', email) formData.append('confirm_email', confirm_email) formData.append('confirm', String(confirm)) await resaleTicket(formData, activeTicket.hash) const response = await getOrderDetails(orderId) onGetOrdersSuccess(response) const data = _get(response, 'data.attributes') const updatedData = { ...data } updatedData?.tickets?.forEach((ticket: ITicketTypes) => { if (ticket.hash === activeTicket.hash) { ticket.is_sellable = false ticket.is_on_sale = true } }) setData(updatedData) onResaleTicketSuccess() } catch (error) { onResaleTicketError(error) } finally { setShowResaleModal(false) setResaleTicketLoading(false) } } const handleRemoveFromResale = (ticket: ITicketTypes) => { setShowRemoveResaleModal(true) setActiveTicket(ticket) } const onCloseRemoveResale = () => { setShowRemoveResaleModal(false) setActiveTicket(null) } const onConfirmRemoveResale = async () => { if (removeFromResaleLoading) { return } try { setRemoveFromResaleLoading(true) await removeFromResale(activeTicket.hash) const response = await getOrderDetails(orderId) onGetOrdersSuccess(response) const data = _get(response, 'data.attributes') const updatedData = { ...data } updatedData?.tickets?.forEach((ticket: ITicketTypes) => { if (ticket.hash === activeTicket.hash) { ticket.is_sellable = true ticket.is_on_sale = false } }) setData(updatedData) onRemoveFromResaleSuccess() } catch (error) { onRemoveFromResaleError(error) } finally { setShowRemoveResaleModal(false) setRemoveFromResaleLoading(false) } } const handleOrderCustomFieldsUpdate = async (values: Record) => { setShowOrderCustomFieldsSection(false) try { // Collect all updatable and non updatable values for bulk update const fullUpdatableValues = orderNotUpdatableCustomFields.reduce( (acc, customField) => { acc[customField.name] = customField.value return acc }, { ...values } ) const eventId = _get(data, 'event_id') const response = await updateOrderCustomFields( eventId, orderId, fullUpdatableValues ) const updatedCustomFields = _get(response, 'data.data.attributes', []) setData((prevState: Record) => ({ ...prevState, data_capture: updatedCustomFields, })) onUpdateOrderCustomFieldsSuccess(response) } catch (error) { onUpdateOrderCustomFieldsError(error) } } const handleTicketHoldersUpdate = async ( values: Record, ticketHash: string ) => { try { const eventId = _get(data, 'event_id') const response = await updateTicketHoldersCustomFields(eventId, values, ticketHash) const updatedFields = _get(response, 'data.data.attributes', []) const notUpdatedFields = ticketHoldersCustomFields.filter( (field: CustomFieldTypes) => field.ticketHash !== ticketHash ) setData((prevState: Record) => ({ ...prevState, ticket_data_capture: [...updatedFields, ...notUpdatedFields], })) onUpdateTicketHolderCustomFieldsSuccess(response) } catch (error) { onUpdateTicketHolderCustomFieldsError(error) } } const theme = createTheme(themeOptions ?? {}) if (isLoading || _isEmpty(data)) { if (displayLoading) { return ( ) } return null } return (

Order Details

{!_isEmpty(orderUpdatableCustomFields) && ( setShowOrderCustomFieldsSection(true)} /> )}
Order Summary

{orderSummery}

{!_isEmpty(orderCustomFields) && ( <>
{orderCustomFields.map((customField: CustomFieldTypes) => (
{customField.label} : {renderCustomFieldValue(customField)}
))}
{!_isEmpty(orderUpdatableCustomFields) && (

Aditional Information Request

setShowOrderCustomFieldsSection(false)} />
)} )} {!data?.disable_referral && ( <> {referralTitle && (

{referralTitle}

)}
{data?.sales_referred ? (

{`So far, you’ve referred ${data.sales_referred} tickets`}

) : null}
)} {itemsTitle &&

{itemsTitle}

} {_map(columnsProps, item => ( {item.label || ''} ))} {data?.items?.ticket_types?.map((ticket: TicketTypes, index: number) => data?.tickets && !data?.tickets[0].is_table ? ( Ticket Type: {ticket.name} {ticket.currency + ticket.price} {ticket.quantity} {ticket.currency + ticket.total} ) : ( Ticket Type: {ticket.name} {ticket.currency + ticket.price} {ticket.guests_count} {ticket.deposit_paid} {ticket.remaining} ) )} {data?.items?.add_ons?.map((ticket: TicketTypes, index: number) => (
Add-On
{ticket.groupName && `${ticket.groupName}: `} {ticket.name}
{ticket.currency + ticket.price} {ticket.quantity} {ticket.currency + ticket.total}
))} Total {getTotal(data)}
{showResaleModal && ( )} {showRemoveResaleModal && ( )}
) }