{"version":3,"file":"index-B6iVQrRi.js","sources":["../../../../core/auth.tsx","../../../../core/config.ts","../../../../core/apm.ts","../../../../types/index.ts","../../../../ui/Logo/index.tsx","../../../../ui/Page/footer.tsx","../../../../ui/Page/index.tsx","../../../../ui/CoverageItem/index.tsx","../../../../core/errors.ts","../../../../core/api/base.ts","../../../../core/api/merchant.ts","../../../../core/analytics/attribution.ts","../../../../ui/Spinner/index.tsx","../../../../ui/Text/skeleton.tsx","../../../../ui/Form/builder.tsx","../../../../ui/Form/text.tsx","../../../../ui/Form/select.tsx","../../../../ui/Loadable/index.tsx","../../../../ui/Button/index.tsx","../../../../ui/Banner/index.tsx","../../../../ui/Form/switch.tsx","../../../../ui/Form/checkbox.tsx","../../../partners/pages/personalization/forms.tsx","../../pages/rental/index.tsx","../../pages/landing.tsx","../../../../core/analytics/googletags.ts","../../../../core/api/user.ts","../../../../core/debounce.ts","../../../../core/hubspot.tsx","../../../../ui/ErrorBoundary/index.tsx","../../../partners/components/Spinner/index.tsx","../../../partners/components/Button/index.tsx","../../../../core/analytics/analytics.ts","../../../../core/stripe.tsx","../../../../ui/Table/index.tsx","../../../partners/pages/rental/components.tsx","../../../../ui/Badge/index.tsx","../../../partners/pages/rental/RentalBookingDetailsPage.tsx","../../../partners/components/Page/footer.tsx","../../../partners/components/Page/index.tsx","../../../../core/mapbox.tsx","../../../../ui/Form/address.tsx","../../../partners/pages/rental/RentalCustomerForm.tsx","../../../partners/pages/rental/RentalCompletionPage.tsx","../../../partners/pages/rental/RentalAgreement.tsx","../../index.tsx"],"sourcesContent":["import * as React from 'react';\nimport { MerchantUser, User } from '@oysterjs/types';\n\ninterface Auth {\n Token?: string;\n // TODO: the backend currently returns a separate field, `MerchantUser`\n // for merchant users. We should unify these based on the typing here.\n User?: T;\n MerchantUser?: MerchantUser;\n}\n\nexport type SetAuthFn = (auth: Auth) => void;\n\nexport const useAuth = (): [Auth, SetAuthFn] => {\n const getAuth = () => {\n const data = window.localStorage.getItem('oyster_token');\n if (data) {\n const auth: Auth = JSON.parse(data);\n return auth;\n }\n\n return {};\n };\n\n const setAuth = (auth: Auth) => {\n window.localStorage.setItem('oyster_token', JSON.stringify(auth));\n _setAuth(auth);\n };\n\n const [auth, _setAuth] = React.useState(getAuth());\n\n React.useEffect(() => {\n const updateAuth = () => setAuth(getAuth());\n window.addEventListener('storage', updateAuth);\n return () => window.removeEventListener('storage', updateAuth);\n }, []);\n\n return [auth, setAuth];\n};\n\nexport const getToken = (): string | null => {\n const data = window.localStorage.getItem('oyster_token');\n return !data ? null : JSON.parse(data)?.Token;\n};\n\nexport const getUser = (): T | null => {\n const data = window.localStorage.getItem('oyster_token');\n return !data ? null : JSON.parse(data)?.User || JSON.parse(data)?.MerchantUser;\n};\n\nexport const resetToken = (redirect?: string): void => {\n window.localStorage.removeItem('oyster_token');\n window.location.href = `/signin${redirect ? `?redirect=${encodeURIComponent(redirect)}` : ''}`;\n};\n","export type Environment = 'production' | 'staging' | 'dev' | 'local';\n\nexport type Service = 'getoyster' | 'dashboard' | 'partners' | 'oysterjs' | 'webhooks';\nexport type Backend = 'admin' | 'api' | 'merchant' | 'integrate' | 'metrics' | 'statics';\n\nconst getEnvironment = (): Environment => {\n if (typeof window === 'undefined') {\n return 'local';\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const environment = process.env.OYSTER_ENVIRONMENT || window?.oyster?.opts?.environment;\n switch (environment) {\n case 'production':\n case 'staging':\n case 'dev':\n case 'local':\n return environment;\n default:\n return 'local';\n }\n};\n\nconst getApiBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://api.withoyster.com';\n case 'staging':\n return 'https://api.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('api');\n case 'local':\n return 'http://localhost:8080';\n }\n};\n\nconst getAdminBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://admin.oysterinc.net';\n case 'staging':\n return 'https://admin.staging.oysterinc.net';\n case 'dev':\n return devServiceUrl('admin');\n case 'local':\n return 'http://localhost:8080';\n }\n};\n\nconst getMerchantBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://merchant.withoyster.com';\n case 'staging':\n return 'https://merchant.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('merchant');\n case 'local':\n return 'http://localhost:8084';\n }\n};\n\nconst getMetricsBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://mtx.withoyster.com';\n case 'staging':\n return 'https://mtx.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('metrics');\n case 'local':\n return 'http://localhost:8083';\n }\n};\n\nconst getStaticsBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://s.withoyster.com';\n case 'staging':\n return 'https://s.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('statics');\n case 'local':\n return 'http://localhost:8081';\n }\n};\n\nconst getIntegrateBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://integrate.withoyster.com';\n case 'staging':\n return 'https://integrate.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('integrate');\n case 'local':\n return 'http://localhost:8085';\n }\n};\n\nconst getOysterJsBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://js.withoyster.com';\n case 'staging':\n return 'https://js.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('oysterjs');\n case 'local':\n return 'http://localhost:8001';\n }\n};\n\nconst getDashboardBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://dashboard.withoyster.com';\n case 'staging':\n return 'https://dashboard.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('dashboard');\n case 'local':\n return 'http://localhost:8180';\n }\n};\n\nconst getGetOysterBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://get.withoyster.com';\n case 'staging':\n return 'https://get.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('getoyster');\n case 'local':\n return 'http://localhost:8181';\n }\n};\n\nconst getPartnersBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://partners.withoyster.com';\n case 'staging':\n return 'https://partners.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('partners');\n case 'local':\n return 'http://localhost:8182';\n }\n};\n\nconst getWebhooksBaseUrl = (): string => {\n switch (getEnvironment()) {\n case 'production':\n return 'https://webhooks.withoyster.com';\n case 'staging':\n return 'https://webhooks.staging.withoyster.com';\n case 'dev':\n return devServiceUrl('webhooks');\n case 'local':\n return 'http://localhost:8080';\n }\n};\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nconst getServiceName = (): Service => (process.env.SERVICE_NAME as Service) || '';\n\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nconst getServiceVersion = (): string => process.env.SERVICE_VERSION || '';\n\nconst devServiceUrl = (service: string) => {\n // Get the user from the URL\n const [, user] = window.location.host.split('.');\n\n // Host will be in the format of {service}.{user}.dev.oysterinc.net\n return `https://${service}.${user}.dev.oysterinc.net`;\n};\n\nconst getSecret = (secretName: string, devSecret?: string) =>\n devSecret || window?.['oyster']?.['opts']?.[secretName];\n\n// Configuration defines the various configuration values that can\n// be set on the app\ntype StaticConfiguration = {\n readonly serviceName: Service;\n readonly serviceVersion: string;\n readonly environment: Environment;\n readonly serviceBaseUrl: { [K in Service]: string };\n readonly backendBaseUrl: { [K in Backend]: string };\n readonly secrets: {\n readonly mapboxPublicKey?: string;\n readonly shopifyPublicKey?: string;\n readonly stripePublicKey?: string;\n readonly coterieStripePublicKey?: string;\n readonly sentryDsn?: string;\n };\n};\n\ntype DynamicConfiguration = {\n readonly merchant?: {\n readonly id?: string;\n readonly apiKey?: string;\n readonly integrationId?: string;\n };\n};\n\nlet dynamicConfig: DynamicConfiguration = {};\nexport const configure = (opts: DynamicConfiguration) => {\n dynamicConfig = opts;\n};\n\nexport type Configuration = StaticConfiguration & DynamicConfiguration;\n\n// config builds and exports the configuration for usage.\nexport default (): Configuration => ({\n serviceName: getServiceName(),\n serviceVersion: getServiceVersion(),\n environment: getEnvironment(),\n serviceBaseUrl: {\n dashboard: getDashboardBaseUrl(),\n getoyster: getGetOysterBaseUrl(),\n partners: getPartnersBaseUrl(),\n oysterjs: getOysterJsBaseUrl(),\n webhooks: getWebhooksBaseUrl()\n },\n backendBaseUrl: {\n admin: getAdminBaseUrl(),\n api: getApiBaseUrl(),\n merchant: getMerchantBaseUrl(),\n integrate: getIntegrateBaseUrl(),\n metrics: getMetricsBaseUrl(),\n statics: getStaticsBaseUrl()\n },\n secrets: {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n mapboxPublicKey: getSecret('mapboxPublicKey', process.env.MAPBOX_PUBLIC_KEY),\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n shopifyPublicKey: getSecret('shopifyPublicKey', process.env.SHOPIFY_PUBLIC_KEY),\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n stripePublicKey: getSecret('stripePublicKey', process.env.STRIPE_PUBLIC_KEY),\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n coterieStripePublicKey: getSecret(\n 'coterieStripePublicKey',\n process.env.COTERIE_STRIPE_PUBLIC_KEY\n ),\n sentryDsn: process.env.SENTRY_DSN\n },\n ...dynamicConfig\n});\n","import * as Sentry from '@sentry/react';\nimport { getUser } from './auth';\nimport config from './config';\n\nclass Apm {\n constructor(private session: Session) {}\n\n // eslint-disable-next-line\n captureError(error: any) {\n if (Sentry.isInitialized()) {\n Sentry.captureException(error);\n }\n }\n\n setUserContext(userObject: { id?: string; email?: string }) {\n if (Sentry.isInitialized()) {\n Sentry.setUser(userObject);\n }\n this.session.userId = userObject.id?.toString() || this.session.userId;\n }\n\n getSessionId() {\n return Sentry.getReplay()?.getReplayId();\n }\n}\n\nlet apm: Apm;\n\ninterface Session {\n userId: string;\n pageLoadId: string;\n merchantId?: string;\n}\n\nconst initSession = (): Session => {\n const getRandomString = (len: number): string => {\n const characters = '0123456789abcdef';\n let str = '';\n for (let i = 0; i < len; i++) {\n str += characters.charAt(Math.floor(Math.random() * characters.length));\n }\n return str;\n };\n\n // Check if we have an authenticated user ID\n let userId = getUser()?.ID;\n\n // Check if we already stored an ID locally\n if (!userId) {\n userId = window.localStorage.getItem('oyster_user_id') || undefined;\n }\n\n // Otherwise, generate an ID and store it\n if (!userId) {\n userId = getRandomString(24);\n window.localStorage.setItem('oyster_user_id', userId);\n }\n\n return {\n userId,\n pageLoadId: getRandomString(24)\n };\n};\n\nexport const init = (): void => {\n const session = initSession();\n\n Sentry.init({\n dsn: config().secrets.sentryDsn,\n integrations: [\n Sentry.browserTracingIntegration(),\n Sentry.browserProfilingIntegration(),\n Sentry.captureConsoleIntegration({\n levels: ['error']\n }),\n Sentry.extraErrorDataIntegration(),\n Sentry.httpClientIntegration(),\n Sentry.reactRouterV5BrowserTracingIntegration({ history }),\n Sentry.replayIntegration({\n networkDetailAllowUrls: [\n window.location.origin,\n config().backendBaseUrl.api,\n config().backendBaseUrl.integrate,\n config().backendBaseUrl.merchant,\n config().backendBaseUrl.metrics,\n config().backendBaseUrl.statics\n ],\n networkCaptureBodies: true,\n networkRequestHeaders: ['X-Merchant-Integration-ID', 'X-Merchant-API-Key'],\n maskAllText: false,\n blockAllMedia: false\n }),\n Sentry.sessionTimingIntegration()\n ],\n\n autoSessionTracking: true,\n enabled: true,\n enableTracing: true,\n\n environment: config().environment,\n release: config().serviceVersion,\n\n // Set tracesSampleRate to 1.0 to capture 100%\n // of transactions for performance monitoring.\n tracesSampleRate: 1.0,\n\n // Set `tracePropagationTargets` to control for which URLs distributed tracing should be enabled\n tracePropagationTargets: [\n config().backendBaseUrl.api,\n config().backendBaseUrl.integrate,\n config().backendBaseUrl.merchant,\n config().backendBaseUrl.metrics,\n config().backendBaseUrl.statics\n ],\n\n // Capture Replay for 100% of all sessions,\n // plus for 100% of sessions with an error\n replaysSessionSampleRate: 1.0,\n replaysOnErrorSampleRate: 1.0\n });\n\n apm = new Apm(session);\n};\n\n// eslint-disable-next-line\n// @ts-ignore\nexport default (): Apm => apm;\n","///////////////////////////////////////////////////////\n// SDK-specific types //\n///////////////////////////////////////////////////////\n\nexport type EcommercePlatform = 'shopify' | 'magento' | 'custom';\n\nexport type DeepPartial = T extends Date | File | number | string\n ? T\n : T extends object\n ? {\n [P in keyof T]?: DeepPartial;\n }\n : T;\n\nexport interface InitOptions {\n apiKey: string;\n integrationID?: string;\n platform?: EcommercePlatform;\n apiBaseUrl?: string;\n metricsBaseUrl?: string;\n staticsBaseUrl?: string;\n environment?: string;\n}\n\n///////////////////////////////////////////////////////\n// Types corresponding to product models //\n///////////////////////////////////////////////////////\n\nexport enum ProductType {\n bike = 'bike',\n offroad = 'offroad_vehicle',\n motorcycle = 'motorcycle',\n jewelry = 'jewelry',\n phone = 'phone',\n electronics = 'electronics'\n}\n\nexport enum AdditionalMerchantProductType {\n collectibles = 'collectibles',\n furniture = 'furniture',\n fashion = 'fashion',\n food_and_beverage = 'food_and_beverage',\n beauty_and_supplements = 'beauty_and_supplements',\n outdoor_sports = 'outdoor_sports',\n other = 'other'\n}\n\nexport type MerchantProductType = ProductType | AdditionalMerchantProductType;\n\nexport interface Product {\n ID?: string;\n Type: ProductType;\n SKU: string;\n Name: string;\n Description: string;\n ImageURL: string;\n Quantity: number;\n Price: Price;\n Pending?: boolean;\n HasNotReceived?: boolean;\n Details: T;\n}\n\nexport enum BikeType {\n roadTrack = 'road_track',\n mountain = 'mountain',\n hybridCruiser = 'hybrid_cruiser',\n recumbent = 'recumbent',\n tandem = 'tandem',\n bmx = 'bmx',\n tricycle = 'tricycle',\n electric = 'electric'\n}\n\nexport enum BikeFrameType {\n none = '',\n aluminum = 'aluminum',\n carbonFiber = 'carbon_fiber',\n steel = 'steel',\n titatium = 'titanium',\n wood = 'wood',\n other = 'other'\n}\n\nexport enum BikePowerSource {\n none = '',\n throttleAssist20MPH = 'throttle_assist_20_mph',\n pedalAssist20MPH = 'pedal_assist_20_mph',\n pedalAssist28MPH = 'pedal_assist_28_mph',\n other = 'other'\n}\n\nexport enum MotorProductType {\n // Motorcycles\n preferred_tour = 'preferred_tour',\n tour = 'tour',\n sport_tour = 'sport_tour',\n non_touring_bmw = 'non_touring_bmw',\n big_twin = 'big_twin',\n low_surcharge = 'low_surcharge',\n high_surcharge = 'high_surcharge',\n professional_racing_surcharge = 'professional_racing_surcharge',\n naked_sport = 'naked_sport',\n sportster = 'sportster',\n cruiser = 'cruiser',\n high_performance_cruiser = 'high_performance_cruiser',\n moped = 'moped',\n scooter = 'scooter',\n street_bike = 'street_bike',\n off_road_trail_bike = 'off_road_trail_bike',\n tour_trike = 'tour_trike',\n\n // Offroad vehicles\n sport_performance_atv = 'sport_performance_atv',\n recreation_utility_atv = 'recreation_utility_atv',\n super_utility_atv = 'super_utility_atv',\n golf_cart = 'golf_cart'\n}\n\nexport enum ActivationSource {\n TrackingNumber = 'TrackingNumber',\n SetStartDate = 'SetStartDate',\n ManuallyActivate = 'ManuallyActivate'\n}\n\nexport interface ActivationTrigger {\n Source: ActivationSource;\n TrackingNumber?: string;\n StartDate?: string;\n}\n\nexport interface MotorProduct {\n ModelYear: string;\n PurchaseYear: string;\n\n Type: MotorProductType;\n Make: string;\n Model: string;\n VIN: string;\n CCSize: string;\n\n EstimatedAnnualMileage: string;\n AccessoryValue?: Price;\n\n HasElectronicAlarm?: boolean;\n HasTrackingSystem?: boolean;\n HasLienHolder?: boolean;\n IsPerformanceEnhanced?: boolean;\n IsStructurallyModified?: boolean;\n}\n\nexport const MotorProductValidationKeys: (keyof MotorProduct)[] = [\n 'ModelYear',\n 'PurchaseYear',\n\n 'Type',\n 'Make',\n 'Model',\n 'VIN',\n 'CCSize',\n\n // 'EstimatedAnnualMileage', - this one is checked on a later page\n 'AccessoryValue'\n];\n\nexport interface BikeProduct {\n Type: BikeType;\n FrameType: BikeFrameType;\n PowerSource?: BikePowerSource;\n CanUnlock?: boolean;\n IsPendingSerialNumber?: boolean;\n StartLater?: boolean;\n\n ModelYear: string;\n PurchaseYear: string;\n Make: string;\n Model: string;\n FrameSerialNumber: string;\n IsSecondHandPurchase: boolean;\n\n TotalInsuredValue?: Price;\n}\n\nexport const BikeProductValidationKeys: (keyof BikeProduct)[] = [\n 'Type',\n 'FrameType',\n 'PowerSource',\n 'CanUnlock',\n 'ModelYear',\n 'PurchaseYear',\n 'Make',\n 'Model',\n 'FrameSerialNumber',\n 'TotalInsuredValue'\n];\n\nexport enum ElectronicsType {\n laptop = 'laptop',\n iPhone = 'iphone',\n smartPhone = 'smartphone',\n iPad = 'ipad',\n smallElectronics = 'small_electronics',\n gamingSystem = 'gaming_system',\n eReaderKindle = 'ereader_kindle',\n tablet = 'tablet'\n}\n\nexport interface ElectronicsProduct {\n Type: ElectronicsType;\n Manufacturer: string;\n Model: string;\n SerialNumber: string;\n PurchaseReceiptFileIDs?: string[];\n\n _PurchaseReceiptFiles?: File[];\n}\n\nexport const ElectronicsProductValidationKeys: (keyof ElectronicsProduct)[] = [\n 'Type',\n 'Manufacturer',\n 'Model',\n 'SerialNumber'\n];\n\nexport interface JewelryProduct {\n Type: string;\n Metal: string;\n Brand: string;\n StoneType: string;\n StoneWeight: string;\n StoneCarat: string;\n StoneColor: string;\n StoneClarity: string;\n InSafe: boolean;\n IsNewPurchase: boolean;\n AppraisalFileIDs?: string[];\n\n _AppraisalFiles?: File[];\n}\n\nexport const JewelryProductValidationKeys: (keyof JewelryProduct)[] = [\n 'Type',\n 'Metal',\n 'Brand',\n 'StoneType',\n 'StoneWeight',\n 'StoneCarat',\n 'StoneColor',\n 'StoneClarity'\n];\n\n///////////////////////////////////////////////////////\n// Types corresponding to policy models //\n///////////////////////////////////////////////////////\n\nexport enum Cadence {\n year = 'year',\n month = 'month'\n}\n\nexport enum PolicyState {\n unknown = '',\n offerSubmitted = 'offer_submitted',\n applicationSubmitted = 'application_submitted',\n quoteActive = 'quote_active',\n quoteSigned = 'quote_signed',\n policyBinding = 'policy_binding',\n policyInforce = 'policy_inforce',\n policyCanceled = 'policy_canceled',\n policyExpired = 'policy_expired'\n}\n\nexport enum PolicyType {\n bike = 'bike',\n markelBike = 'markel_bike',\n markelOffroad = 'markel_offroad',\n markelMotorcycle = 'markel_motorcycle',\n minicoJewelry = 'minico_jewelry',\n chubbJewelry = 'chubb_jewelry',\n worthAveElectronics = 'worth_ave_electronics'\n}\n\nexport interface PolicyTableValues {\n CreatedAt: Date;\n InsuredItems: Product[];\n}\n\nexport interface Policy {\n ID: string;\n Name: string;\n UserID: string;\n MerchantID: string;\n\n Type: PolicyType;\n State: PolicyState;\n\n InsuredItems: Product[];\n Underwriting: Underwriting;\n Coverage: Coverage;\n ReferralChannelInfo?: PolicyReferralChannelInfo;\n\n Price?: Price;\n PaymentCadence: Cadence;\n DisableAutoRenew: boolean;\n\n CreatedAt: Date;\n StartedAt: Date;\n ExpiresAt: Date;\n}\n\nexport interface Price {\n Amount: number;\n Currency: string;\n}\n\nexport interface Coverage {\n Deductible: DiscreteOption;\n Options: Option[];\n ActivationTrigger?: ActivationTrigger;\n}\n\nexport interface PolicyReferralChannelInfo {\n ReferralChannel: ReferralChannelType;\n ReferralSubChannel: ReferralSubChannel;\n Settings: MerchantReferralSettings | MarketingCampaignSettings | DirectReferralSettings;\n}\n\nexport enum ReferralSubChannel {\n product = 'ProductPage',\n addToCartButton = 'AddToCartButton',\n cart = 'CartPage',\n confirm = 'OrderConfirmationPage',\n defaultInsurance = 'DefaultInsurance',\n unknown = ''\n}\n\nexport interface MerchantReferralSettings {\n MerchantID: string;\n IntegrationID: string;\n}\n\nexport interface MarketingCampaignSettings {\n Source: string;\n Campaign: string;\n Term: string;\n Medium: string;\n PageHistory: string[];\n}\n\nexport interface DirectReferralSettings {\n Parameters: string;\n PageHistory: string[];\n}\n\nexport enum ReferralChannelType {\n ReferralChannelMerchant = 'Merchant',\n ReferralChannelMarketingCampaign = 'Marketing Campaign',\n ReferralChannelDirect = 'Direct'\n}\n\nexport enum BikeUsageType {\n casual = 'casual',\n fitness = 'fitness',\n commute = 'commute',\n competition = 'competition'\n}\n\nexport enum MarkelPersonalCharacteristicFlag {\n homeowner = 'homeowner',\n motorcycle_endorsed = 'motorcycle_endorsed',\n taken_safety_course = 'taken_safety_course',\n taken_mature_driver_course = 'taken_mature_driver_course'\n}\n\nexport interface MarkelMotorCriteria {\n ZipCode: string;\n\n YearsOfExperience: string;\n MinorViolations: string;\n MajorViolations: string;\n AtFaultAccidents: string;\n\n DriversLicenseNumber: string;\n DriversLicenseState: string;\n\n PersonalCharacteristicFlags: MarkelPersonalCharacteristicFlag[];\n}\n\nexport interface BikeCriteria {\n ZipCode: string;\n UsageTypes: BikeUsageType[];\n\n StorageAddressLine1: string;\n StorageAddressLine2: string;\n StorageCity: string;\n StorageState: string;\n StorageZipCode: string;\n ResidentialIsStorage: boolean;\n}\n\nexport interface MarkelBikeCriteria {\n ZipCode: string;\n UsageTypes: BikeUsageType[];\n\n StorageAddressLine1: string;\n StorageAddressLine2: string;\n StorageCity: string;\n StorageState: string;\n StorageZipCode: string;\n ResidentialIsStorage: boolean;\n YearsOfExperience: string;\n}\n\nexport enum JewelryUnderwritingFlag {\n default = 'default',\n exhibition = 'exhibition',\n bankruptcy = 'bankruptcy',\n judgment = 'judgment',\n conviction = 'conviction'\n}\n\nexport enum JewelryStorageLocationFlag {\n central_station_fire = 'central_station_fire',\n burglar_alarm = 'burglar_alarm',\n central_station_burglar_alarm = 'central_station_burglar_alarm',\n deadbolts = 'deadbolts',\n below_ground = 'below_ground',\n off_the_ground = 'off_the_ground',\n near_fire_hydrant = 'near_fire_hydrant',\n flood_zone = 'flood_zone',\n has_doorman = 'has_doorman',\n storage_climate_controlled = 'storage_climate_controlled'\n}\n\nexport interface JewelryPriorLoss {\n lossIdentifier: string;\n dateOfLoss: Date;\n lossAmount: number;\n description: string;\n}\n\nexport interface JewelryCriteria {\n ZipCode: string;\n PriorLosses: JewelryPriorLoss[];\n UnderwritingFlags: JewelryUnderwritingFlag[];\n UnderwritingJustification: string;\n\n StorageStreetAddress: string;\n StorageAptFloor: string;\n StorageAptUnit: string;\n StorageCity: string;\n StorageState: string;\n StorageZipCode: string;\n StorageIsResidential: boolean;\n\n ConstructionType: string;\n ConstructionYear: string;\n StorageLocationFlags: JewelryStorageLocationFlag[];\n\n HasAdditionalInsured: boolean;\n AdditionalInsuredFirstName: string;\n AdditionalInsuredLastName: string;\n\n IsCurrentlyInsured: boolean;\n CurrentInsurerName: string;\n}\n\nexport interface ChubbAddress {\n line1: string;\n line2: string;\n city: string;\n postalCode: string;\n stateOrProvinceName: string;\n}\n\nexport interface ChubbLoss {\n lossIdentifier: string;\n causeOfLossCode: string;\n sourceOfLossCode: string;\n causeOfLossDescription: string;\n dateOfLoss: string;\n lossPaidDate: string;\n lossPaidAmount: number;\n lossType: string;\n lossCatastrophe: boolean;\n lossStatus: string;\n}\nexport interface ChubbJewelryCriteria {\n ZipCode: string;\n PriorLosses: ChubbLoss[];\n\n StorageAddress: ChubbAddress;\n StorageIsResidential: boolean;\n\n ConstructionType: string;\n ResidenceType: string;\n\n AcceptConsumerDisclosure: string;\n\n HasAdditionalInsured: boolean;\n AdditionalInsuredFirstName: string;\n AdditionalInsuredLastName: string;\n AdditionalInsuredOccupation: string;\n AdditionalInsuredOccupationDetails: string;\n AdditionalInsuredDateOfBirth: { Day: string; Month: string; Year: string };\n\n IsCoveredItemsElevated: boolean;\n IsStoredInClimateControlledStorage: boolean;\n\n OccupationDetails: string;\n OtherOccupationDetails: string;\n\n CentralStationFireAlarm: boolean;\n TwentyFourHourSecurity: boolean;\n SignalContinuity: boolean;\n FullTimeCaretaker: boolean;\n GatedCommunity: boolean;\n GatedCommunityPatrol: boolean;\n FiftyPercentJewelryKeptInVault: boolean;\n SafeAtHome: boolean;\n HasInHouseEmployees: boolean;\n InHouseEmployees: string;\n InsuredTravel: string;\n AverageJewelryValueOnTravel: number;\n JewelrySafeguardOnTravel: string;\n JewelrySafeguardAtHomeInsuredOnTravel: string;\n}\n\nexport interface Underwriting {\n Criteria:\n | MarkelMotorCriteria\n | BikeCriteria\n | MarkelBikeCriteria\n | JewelryCriteria\n | ChubbJewelryCriteria;\n Insured: Insured;\n Underwriter?: string;\n}\n\nexport type OptionDetails =\n | BooleanOption\n | DiscreteOption\n | MultiDiscreteOption\n | RangeOption\n | TextOption;\n\nexport enum OptionType {\n boolean = 'boolean',\n discrete = 'discrete',\n multi_discrete = 'multi_discrete',\n range = 'range',\n text = 'text'\n}\n\nexport interface Option {\n ID: string;\n Name: string;\n Description: string;\n Required: boolean;\n Enabled: boolean;\n Type: OptionType;\n Option: OptionDetails;\n}\n\nexport interface BooleanOption {\n ValueLabel: string;\n}\n\nexport interface DiscreteOption {\n Value: string;\n AllowedValues: string[];\n AllowedValueDescriptions: Record;\n}\n\nexport interface MultiDiscreteOption {\n Values: string[];\n AllowedValues: string[];\n AllowedValueDescriptions?: Record;\n}\n\nexport interface RangeOption {\n Value: number;\n MinValue: number;\n MaxValue: number;\n Step: number;\n}\n\nexport interface TextOption {\n Value: string;\n Validators: string[];\n}\n\nexport enum Gender {\n male = 'male',\n female = 'female',\n non_binary = 'non_binary',\n other = 'other'\n}\n\nexport interface Insured {\n FirstName: string;\n LastName: string;\n Email: string;\n Phone?: string;\n Occupation?: string;\n Gender?: Gender;\n MaritalStatus?:\n | 'married'\n | 'single'\n | 'divorced'\n | 'separated'\n | 'widowed'\n | 'civil_union'\n | 'domestic_partnership';\n DateOfBirth?: { Day: string; Month: string; Year: string };\n\n AddressLine1?: string;\n AddressLine2?: string;\n AddressCity?: string;\n AddressState?: string;\n AddressZipCode?: string;\n}\n\n///////////////////////////////////////////////////////\n// Types corresponding to files and metadata //\n///////////////////////////////////////////////////////\n\nexport interface AttachmentFile {\n ID: string;\n Name: string;\n Type: string;\n Size: number;\n\n Attachment?: AttachmentDetails;\n}\n\nexport interface AttachmentDetails {\n FileID: string;\n RefID: string;\n Role: DefaultFileRoles;\n EntityType: string;\n\n CreatedAt: Date;\n UpdatedAt: Date;\n}\n\nexport enum DefaultFileRoles {\n jewelryAppraisal = 'JewelryAppraisal',\n purchaseReceipt = 'PurchaseReceipt',\n\n waiverClaimAttachment = 'WaiverClaimAttachment',\n waiverLDWDocument = 'LossDamageWaiver',\n signedRentalAgreement = 'SignedRentalAgreement',\n merchantRentalPDTA = 'ProgramDescriptionTermsAccepance',\n\n commercialDocument = 'CommercialDocument',\n unknown = 'Unknown'\n}\n\n///////////////////////////////////////////////////////\n// Types corresponding to claim models //\n///////////////////////////////////////////////////////\n\nexport enum ClaimState {\n unknown = '',\n awaitingProcessing = 'awaiting_processing',\n collectingInformation = 'collecting_information',\n settled = 'settled',\n denied = 'denied'\n}\n\nexport enum ClaimType {\n // General claim types\n unknown = '',\n theft = 'theft',\n damage = 'damage', // for electronics: includes cracked screen and spills\n injury = 'injury', // bike only\n liability = 'liability', // bike only\n other = 'other',\n\n // Electronics-specific claim types\n electricalBreakdown = 'electrical_breakdown', // only if caused by lightning\n mechanicalBreakdown = 'mechanical_breakdown', // only if warranty is added\n naturalDisaster = 'natural_disaster', // fire, flood, lightning, natural disaster, wind\n waterDamage = 'water_damage' // includes spill\n}\n\nexport interface Claim {\n ID: string;\n State: ClaimState;\n UserID: string;\n Policy: Policy;\n Product: Product;\n\n Types: ClaimType[];\n Sections: ClaimSection[];\n\n IncidentDate: Date;\n Attachments: Record;\n Data: Record;\n\n CreatedAt: Date;\n UpdatedAt: Date;\n}\n\nexport enum ClaimSectionItemType {\n checkbox = 'checkbox',\n select = 'select',\n text = 'text',\n date = 'date',\n location = 'location',\n longText = 'long_text',\n upload = 'upload',\n confirm = 'confirm'\n}\n\nexport type ClaimSectionItemDetails =\n | CheckboxItem\n | SelectItem\n | TextItem\n | DateItem\n | LocationItem\n | LongTextItem\n | UploadItem\n | ConfirmItem;\n\nexport interface ClaimSection {\n ID: string;\n Field: string;\n Title: string;\n Description: string;\n Items: ClaimSectionItem[];\n}\n\nexport interface ClaimSectionItem {\n SubField: string;\n SubTitle?: string;\n Description?: string;\n Type: ClaimSectionItemType;\n Item: ClaimSectionItemDetails;\n}\n\n// eslint-disable-next-line\nexport interface CheckboxItem {}\n\nexport interface SectionItemDescription {\n Title: string;\n Description: string;\n Value: string;\n Icon: string;\n}\n\nexport interface SelectItem {\n AllowedValues: SectionItemDescription[];\n}\n\nexport interface TextItem {\n Required?: boolean;\n}\n\n// eslint-disable-next-line\nexport interface DateItem {}\n\nexport interface LocationItem {\n AddressField: string;\n LongitudeField: string;\n LatitudeField: string;\n}\n\nexport interface LongTextItem {\n Field: string;\n}\n\nexport interface UploadItem {\n Name: string;\n Description: string;\n AllowedTypes: string[];\n MaxSize: number;\n NumRequired: number;\n}\n\nexport interface Confirmation {\n Title: string;\n Description: string;\n}\n\nexport interface ConfirmItem {\n Confirmation: Confirmation[];\n}\nexport interface ClaimAttachment {\n ID: string;\n Name: string;\n Type: string;\n Size: number;\n URL: string;\n}\n\n///////////////////////////////////////////////////////\n// Types corresponding to user models //\n///////////////////////////////////////////////////////\n\nexport interface User {\n ID: string;\n FirstName: string;\n LastName: string;\n Email: string;\n PublicHandle: string;\n CreatedAt: Date;\n}\n\nexport enum ReferralStatus {\n created = 'created',\n fulfilled = 'fulfilled'\n}\n\nexport interface UserReferral {\n ID: string;\n Referrer: {\n UserID: string;\n FirstName: string;\n LastName: string;\n Email: string;\n BusinessName: string;\n };\n Referee: {\n UserID: string;\n FirstName: string;\n LastName: string;\n Email: string;\n BusinessName: string;\n };\n Status: ReferralStatus;\n Reward: number;\n CreatedAt: Date;\n UpdatedAt: Date;\n}\n\nexport interface AccountSummary {\n User?: User;\n}\n\nexport enum VerificationStatus {\n RequiresInput = 'requires_input',\n Processing = 'processing',\n Verified = 'verified',\n Canceled = 'canceled'\n}\n\n///////////////////////////////////////////////////////\n// Types corresponding to general models //\n///////////////////////////////////////////////////////\n\nexport interface ValidationError {\n Field: string;\n SubField?: string;\n Message: string;\n}\n\n///////////////////////////////////////////////////////\n// Types corresponding to merchant models //\n///////////////////////////////////////////////////////\n\nexport interface Address {\n AddressLine1: string;\n AddressLine2?: string;\n\n // Level 1 administrative division depending on country. For example, this is\n // the state in the U.S., the province in Canada, etc.\n Zone: string;\n\n // Level 2 administrative division depending on country. For example, this is\n // the county in the U.S., prefectural city in China, division in India, etc.\n SubZone?: string;\n\n // Level 3 administrative division depending on country. For example, this is\n // the city in the U.S., a muncipality in Austria, a ward in Singapore, etc.\n City: string;\n\n // Country-specific mailing identifier, e.g. ZIP Code in the U.S., Post Code\n // in the U.K., etc.\n PostalCode: string;\n}\n\nexport enum PaymentMethodType {\n Electronic = 'Electronic',\n Check = 'Check',\n Unknown = ''\n}\n\nexport enum SalesChannelType {\n Online = 'Online',\n Dealer = 'Dealer',\n InStore = 'InStore',\n Rental = 'Rental'\n}\n\nexport enum OnlineSalesChannelType {\n Shopify = 'Shopify',\n WooCommerce = 'WooCommerce',\n BigCommerce = 'BigCommerce',\n Lightspeed = 'Lightspeed eCommerce',\n Checkfront = 'Checkfront',\n Adobe = 'Adobe Commerce (Magento)',\n Custom = 'Custom',\n Other = 'Other'\n}\n\nexport enum InStoreSalesChannelType {\n ShopifyPOS = 'Shopify PoS',\n LightspeedRSeries = 'Lightspeed R-Series',\n LightspeedXSeries = 'Lightspeed X-Series',\n Ascend = 'Ascend',\n Edge = 'EDGE',\n Square = 'Square',\n Other = 'Other'\n}\n\nexport enum BusinessOperationType {\n RetailECommerce = 'Retail or E-Commerce',\n Wholesale = 'Wholesale',\n Manufacturing = 'Manufacturing',\n ServiceOrRepair = 'Service or Repair',\n Rental = 'Rental',\n Other = 'Other'\n}\n\nexport enum BusinessInsuranceType {\n BusinessOwners = 'Business Owners',\n CommercialAuto = 'Commercial Auto',\n Cyber = 'Cyber',\n DirectorsAndOfficers = 'Directors and Officers',\n GeneralLiability = 'General Liability',\n JewelersBlock = 'Jewelers Block',\n Other = 'Other',\n Property = 'Property',\n Rental = 'Rental',\n ShippingAndTransportation = 'Shipping and Transportation',\n UmbrellaExcess = 'Umbrella or Excess',\n WorkersCompensation = 'Workers Compensation'\n}\n\nexport enum RentalProductType {\n BikesAndEbikes = 'Bikes and eBikes',\n Kayaks = 'Kayaks',\n Other = 'Other',\n Paddleboards = 'Paddleboards'\n}\n\nexport interface Personalization {\n // Toggle the various types of insurance in the onboarding flow\n BusinessInsuranceEnabled: boolean;\n ProductInsuranceEnabled: boolean;\n RentalInsuranceEnabled: boolean;\n\n // Business insurance settings\n BusinessOperationTypes?: BusinessOperationType[];\n BusinessOperationTypesOtherDesc: string;\n\n BusinessRevenueBreakdownRetail: string;\n BusinessRevenueBreakdownWholesale: string;\n BusinessRevenueBreakdownManufacturing: string;\n BusinessRevenueBreakdownServiceOrRepair: string;\n BusinessRevenueBreakdownRental: string;\n BusinessRevenueBreakdownOther: string;\n BusinessRevenueBreakdownRentalPercentGuided: string;\n\n BusinessTotalPayroll: string;\n\n BusinessManufactureOrWholesaleOwnBrand?: boolean;\n\n BusinessInsuranceTypes?: BusinessInsuranceType[];\n BusinessInsuranceTypesOtherDesc: string;\n\n BusinessNumberOfPriorLosses?: string;\n\n BusinessInsuranceFilloutFormSubmitted: boolean;\n\n // Personal insurance settings\n SalesChannels?: SalesChannelType[];\n\n OnlineSalesChannelType?: OnlineSalesChannelType;\n OnlineSalesChannelName?: string;\n ShopifyAdminURL?: string;\n\n InStoreSalesChannelType?: InStoreSalesChannelType;\n InStoreSalesChannelName?: string;\n\n RentalChannelName?: string;\n\n ProductAnnualRevenue: string;\n\n // Rental insurance settings\n RentalProductTypes?: RentalProductType[];\n RentalProductTypeOtherDesc: string;\n\n RentalMotorizedAssetsExceedEBikeClassification?: boolean;\n\n RentalMaximumAssetValue: string;\n RentalAverageAssetValue: string;\n\n RentalAnnualRevenue: string;\n RentalAnnualVolume: string;\n\n RentalPlatformName: string;\n RentalPointOfSaleName: string;\n}\n\nexport interface BusinessProfile {\n Name: string;\n DBA: string;\n Email: string;\n Phone: string;\n Domain: string;\n Address: Address;\n PaymentMethod: PaymentMethodType;\n\n ProductVerticals?: ProductType[];\n Personalization: Personalization;\n}\n\nexport interface Merchant {\n ID: string;\n MercuryRecipientID: string;\n BusinessProfile: BusinessProfile;\n CreatedAt: Date;\n PublicHandle: string;\n}\n\nexport interface MerchantUser {\n ID: string;\n MerchantID: string;\n\n FirstName: string;\n LastName: string;\n Email: string;\n Phone: string;\n\n ActivationToken?: string;\n CreatedAt: Date;\n}\n\nexport interface MerchantIntegration {\n ID: string;\n Type: MerchantIntegrationType;\n Settings: MerchantIntegrationSettings;\n Status: MerchantIntegrationStatus;\n}\n\nexport enum MerchantIntegrationStatus {\n active = 'Active',\n pending = 'Pending',\n disabled = 'Disabled',\n inactive = 'Inactive'\n}\n\nexport enum MerchantIntegrationType {\n qr_code = 'QRCode',\n referral_link = 'ReferralLink',\n embeddable_marketing_page = 'EmbeddableMarketingPage',\n shopify = 'Shopify',\n custom = 'Custom',\n checkfront = 'Checkfront',\n lsretail_rseries = 'LSRetailRSeries',\n woocommerce = 'WooCommerce',\n not_available = ''\n}\n\nexport type MerchantIntegrationSettings =\n | ShopifyIntegrationSettings\n | LSRetailRSeriesIntegrationSettings\n | QRCodeIntegrationSettings\n | ReferralLinkIntegrationSettings\n | EmbeddableMarketingPageIntegrationSettings\n | WooCommerceIntegrationSettings\n | CustomIntegrationSettings;\n\nexport interface ShopifyIntegrationSettings {\n ShopName: string;\n InsuranceProductID?: string;\n CartPageWidgetEnabled: boolean;\n OrderConfirmationPageWidgetEnabled: boolean;\n ProductPageAddToCartTriggerEnabled: boolean;\n ProductPageWidgetEnabled: boolean;\n UseOysterProductAsIndicator?: boolean;\n OrderConfirmationPageWidgetFirstLoad: Date;\n}\n\nexport interface LSRetailRSeriesIntegrationSettings {\n AccountID: string;\n AccountName: string;\n EmailMarketingEnabled: boolean;\n EmailMarketingRequiresOptIn: boolean;\n EmailMarketingCategoriesEnabled: string[] | null;\n}\n\nexport interface QRCodeIntegrationSettings {\n ReferralLink: string;\n BrandColor?: string;\n FirstDownload?: string;\n}\n\nexport interface ReferralLinkIntegrationSettings {\n ReferralLink: string;\n BrandColor?: string;\n FirstPageLoad?: string;\n}\n\nexport interface EmbeddableMarketingPageIntegrationSettings {\n ReferralLink: string;\n FirstPageLoad?: string;\n}\n\nexport interface WooCommerceIntegrationSettings {\n BaseURL: string;\n OysterVirtualProductID?: number;\n CartPageWidgetEnabled: boolean;\n OrderConfirmationPageWidgetEnabled: boolean;\n ProductPageAddToCartTriggerEnabled: boolean;\n ProductPageWidgetEnabled: boolean;\n}\n\nexport interface CustomIntegrationSettings {\n Data: string;\n}\n\nexport interface MerchantRentalConfiguration {\n ID: string;\n MerchantID: string;\n Details: MerchantRentalConfigurationDetails;\n}\n\nexport interface PublicMerchantRentalConfiguration {\n BillingMode: BillingMode;\n UnifiedWaiverFlowEnabled: boolean;\n AutoRenewWaiver: boolean;\n}\n\nexport enum BillingMode {\n Customer = 'Customer',\n Merchant = 'Merchant'\n}\n\nexport interface MerchantRentalConfigurationDetails {\n BillingMode: BillingMode;\n Pricing: RentalPricingConfiguration;\n State: RentalPolicyState;\n PolicyDocument: AttachmentFile;\n AutoRenewWaiver: boolean;\n UnifiedWaiverFlowEnabled: boolean;\n}\n\nexport enum RentalPolicyState {\n unknown = 'Unknown',\n registered = 'Registered',\n submitted = 'Submitted',\n approved = 'Approved',\n approved_blanket = 'ApprovedBlanketPolicy',\n denied = 'Denied'\n}\n\nexport interface RentalPricingConfiguration {\n Currency: string;\n AssetValueUnitDenominator: number;\n DailyRatingPerValueUnit: number;\n WeeklyRatingPerValueUnit: number;\n MonthlyRatingPerValueUnit: number;\n MinimumPremium: number;\n\n MerchantFeePercent: number;\n MerchantFeeAbs: number;\n MerchantDeductible: number;\n PlatformFeePercent: number;\n PlatformFeeAbs: number;\n}\n\nexport enum MercuryPaymentTypes {\n electronic = 'electronic',\n check = 'check',\n unknown = ''\n}\n\nexport interface ReferralLinkIntegration {\n MerchantName: string;\n IntegrationID: string;\n IntegrationType: MerchantIntegrationType;\n Settings: ReferralLinkIntegrationSettings;\n Disabled?: boolean;\n}\n\nexport enum FeatureFlagExperiments {\n oneliner_widget = 'force_render_oneliner_widget',\n single_click_flow = 'single_click_flow',\n show_logo_on_widget = 'show_logo_on_widget'\n}\n\nexport interface FeatureFlag {\n ID: string;\n Value: boolean;\n}\n\nexport enum MerchantAppType {\n rental = 'rental',\n unknown = ''\n}\n\nexport interface WaiverEntry {\n Waiver?: RentalWaiver;\n Booking?: RentalBooking;\n}\n\nexport enum WaiverState {\n pending = 'Pending',\n canceled = 'Canceled',\n active = 'Active',\n expired = 'Expired',\n upcoming_renewal = 'UpcomingRenewal',\n renewal_canceled = 'RenewalCanceled',\n unknown = ''\n}\n\nexport interface RentalWaiver {\n ID: string;\n MerchantID: string;\n RentalBookingID: string;\n State: WaiverState;\n Details: WaiverDetails;\n}\n\nexport interface WaiverDetails {\n BillingMode: BillingMode;\n WaiverReferenceNumber: string;\n Assets: WaiverAsset[];\n Premium: WaiverPremium;\n PremiumRounding: Price;\n SignatureReference?: AttachmentFile;\n}\n\nexport interface WaiverAsset {\n // Either Asset or BookingLineItem will be present\n Asset?: RentalAsset;\n Premium: WaiverPremium;\n Accessories: AssetAccessory[];\n BookingLineItem?: BookingLineItem;\n}\n\nexport interface WaiverPremium {\n Currency: string;\n Base: number;\n Total: number;\n\n ProcessingFeeAmount: number;\n MerchantFeeAmount: number;\n OysterFeeAmount: number;\n}\n\nexport interface RentalAsset {\n ID: string;\n MerchantID: string;\n\n Type: AssetType;\n Name: string;\n Description: string;\n Value: number;\n Details: AssetDetails;\n}\n\nexport enum AssetType {\n bicycle = 'Bicycle',\n kayak = 'Kayak',\n paddleboard = 'Paddleboard',\n scooter = 'Scooter',\n motorcycle = 'Motorcycle',\n atv = 'ATV',\n other = 'Other'\n}\n\nexport interface AssetDetails {\n SerialNumber: string;\n AvailableAccessories: AssetAccessory[];\n}\n\nexport interface AssetAccessory {\n Name: string;\n Value: number;\n}\n\nexport interface RentalBooking {\n ID: string;\n MerchantID: string;\n\n State: RentalBookingState;\n Details: RentalBookingDetails;\n StartTime: Date;\n EndTime: Date;\n}\n\nexport enum RentalBookingState {\n Unknown = '',\n Confirmed = 'Confirmed'\n}\n\nexport interface BookingLineItem {\n Name: string;\n SKU: string;\n ExternalID: string;\n SerialNumber: string;\n StartDate: Date;\n EndDate: Date;\n Total: number;\n SubTotal: number;\n TaxTotal: number;\n Quantity: number;\n}\n\nexport interface RentalBookingDetails {\n BookingReference: string;\n Insured: Insured;\n Assets?: RentalAsset[];\n Accessories: AssetAccessory[];\n AutoRenew: boolean;\n BookingPlatformDomain?: string;\n BookingLineItems?: BookingLineItem[];\n}\n\nexport interface RentalClaim {\n ID: string;\n MerchantID: string;\n RentalWaiverID: string;\n\n State: RentalClaimState;\n Details: RentalClaimDetails;\n}\n\nexport enum RentalClaimState {\n unknown = '',\n logged = 'Logged',\n submitted = 'Submitted',\n approved = 'Approved',\n denied = 'Denied',\n requires_information = 'RequiresInformation'\n}\n\nexport enum RentalDamageType {\n unknown = '',\n fire = 'Fire',\n theft = 'Theft',\n water = 'Water',\n accident = 'Accident',\n other = 'Other'\n}\n\nexport interface RentalClaimDetails {\n ClaimNumber: string;\n Assets: WaiverAsset[];\n\n IncidentDate: Date;\n IncidentCause: string;\n IncidentAddress: RentalClaimAddress;\n\n DamageType: RentalDamageType;\n\n PoliceReportFiled?: boolean;\n NameOfEmergencyDepartment?: string;\n ReportOrIncidentNumber?: string;\n SourceOfWaterDamage?: string;\n EquipmentExposedToRain?: boolean;\n HasOtherInsuranceCoverage?: boolean;\n}\n\nexport interface RentalClaimAddress {\n AddressLine1?: string;\n AddressLine2?: string;\n AddressCity?: string;\n AddressState?: string;\n AddressZipCode?: string;\n}\n\nexport enum TransactionType {\n credit = 'Credit',\n debit = 'Debit'\n}\n\nexport enum TransactionState {\n created = 'Created',\n pending = 'Pending',\n success = 'Success',\n failure = 'Failure',\n canceled = 'Canceled',\n unknown = ''\n}\n\nexport enum TransactionProcessor {\n stripe = 'Stripe',\n mercury_ach = 'MercuryACH',\n mercury_check = 'MercuryCheck'\n}\n\nexport interface Transaction {\n ID: string;\n PaymentAccountID: string;\n\n Type: TransactionType;\n State: TransactionState;\n Processor: TransactionProcessor;\n ProcessorID: string;\n\n Amount: number;\n Currency: string;\n\n CreatedAt: Date;\n UpdatedAt: Date;\n ClearedAt: Date;\n}\n","import styled from 'styled-components';\n\nconst OysterLogoOldContainer = styled.div<{ inline?: boolean }>`\n display: ${(props) => (props.inline ? 'inline-block' : 'flex')};\n vertical-align: middle;\n justify-content: left;\n align-items: center;\n padding: ${(props) => (props.inline ? '0' : '10px 10px 10px 0px')};\n\n svg {\n vertical-align: middle;\n }\n`;\n\nconst OysterWordMarkContainer = styled.div`\n display: inline-block;\n vertical-align: middle;\n justify-content: left;\n align-items: center;\n padding: 0;\n\n svg {\n vertical-align: middle;\n }\n`;\n\nexport const OysterLogo = ({\n scale,\n color,\n className\n}: {\n scale?: number;\n color?: string;\n className?: string;\n}): JSX.Element => (\n
\n \n \n \n \n \n \n
\n);\n\nexport const OysterLogoOld = ({\n scale,\n inline,\n verticalAlign,\n light,\n color,\n textTransform\n}: {\n scale?: number;\n verticalAlign?: string;\n inline?: boolean;\n light?: boolean;\n color?: string;\n textTransform?: string;\n}): JSX.Element => (\n \n \n \n \n \n \n \n \n \n);\n\nexport const OysterWordMark = ({\n scale,\n forceLight\n}: {\n scale?: number;\n forceLight?: boolean;\n}): JSX.Element => (\n \n \n \n \n \n \n \n \n \n);\n","import config from '@oysterjs/core/config';\nimport { PolicyType } from '@oysterjs/types';\nimport styled from 'styled-components';\n\nconst FooterStandardContainer = styled.div`\n display: flex;\n justify-content: space-between;\n\n @media (max-width: 500px) {\n flex-direction: column;\n justify-content: flex-start;\n align-items: center;\n gap: 10px;\n }\n`;\n\nconst FooterContainer = styled.div`\n padding: 20px 40px;\n display: flex;\n flex-direction: column;\n font-size: 0.8em;\n justify-content: space-between;\n gap: 10px;\n`;\n\nconst FooterLinksContainer = styled.div`\n display: flex;\n\n a {\n &:not(:last-child) {\n margin-right: 20px;\n }\n }\n`;\n\nconst OysterCopyright = (props: { color?: string }) => (\n
\n © 2024 Oyster Technologies, Inc.\n
\n);\n\nconst CustomFooter = (props: { policyType?: PolicyType }) => {\n switch (props.policyType) {\n case PolicyType.chubbJewelry:\n return (\n
\n Insurance described is offered by Oyster Insurance Agency, LLC (California license no.\n 6006158). Insurance is underwritten and provided by Federal Insurance Company (Whitehouse\n Station, NJ), a Chubb ® company. Chubb is the marketing name used to refer to\n subsidiaries of Chubb Limited providing insurance and related services. Coverage is\n subject to the language of the policies as actually issued.\n
\n );\n default:\n return <>;\n }\n};\n\nexport const FooterStandard = (props: { policyType?: PolicyType; color?: string }): JSX.Element => (\n \n \n \n \n \n Contact Us\n \n \n Terms\n \n \n Privacy\n \n \n \n \n \n);\n\nconst FooterMinimalContainer = styled.div`\n padding: 20px 40px;\n display: flex;\n font-size: 0.8em;\n justify-content: space-around;\n`;\n\nexport const FooterMinimal = (props: { color?: string }): JSX.Element => (\n \n \n \n);\n","import React from 'react';\nimport { PolicyType } from '@oysterjs/types';\nimport styled from 'styled-components';\nimport { FooterMinimal, FooterStandard } from './footer';\n\nconst PaneContainer = styled.div<{ gap: number }>`\n display: flex;\n flex-direction: row;\n width: 100%;\n gap: ${(props) => props.gap}px;\n\n @media (max-width: 700px) {\n display: block;\n }\n`;\n\nconst Pane = styled.div<{ gap: number; paneWidth: number }>`\n width: calc(${(props) => props.paneWidth}% - ${(props) => props.gap / 2}px);\n\n @media (max-width: 700px) {\n width: 100%;\n }\n`;\n\nexport const TwoPaneContainer: React.FunctionComponent<\n React.PropsWithChildren<{\n gap?: number;\n leftPaneWidth?: number;\n rightPane: JSX.Element;\n }>\n> = (props) => (\n \n \n {props.children}\n \n \n {props.rightPane}\n \n \n);\n\nexport enum FooterStyle {\n none,\n minimal,\n standard\n}\n\nconst PageContainerDiv = styled.div<{\n width?: number | string;\n marginTop?: number;\n marginRight?: number;\n marginLeft?: number;\n marginBottom?: number;\n}>`\n max-width: ${(props) =>\n props.width ? (isNaN(Number(props.width)) ? props.width : `${props.width}px`) : '1000px'};\n width: 100%;\n margin-top: ${(props) => (props.marginTop !== undefined ? `${props.marginTop}px` : 'auto')};\n margin-right: ${(props) => (props.marginRight !== undefined ? `${props.marginRight}px` : 'auto')};\n margin-bottom: ${(props) =>\n props.marginBottom !== undefined ? `${props.marginBottom}px` : 'auto'};\n margin-left: ${(props) => (props.marginLeft !== undefined ? `${props.marginLeft}px` : 'auto')};\n`;\n\nexport const PageContainer: React.FunctionComponent<\n React.PropsWithChildren<{\n width?: number | string;\n footerStyle?: FooterStyle;\n marginTop?: number;\n marginRight?: number;\n marginLeft?: number;\n marginBottom?: number;\n policyType?: PolicyType;\n footerTextColor?: string;\n }>\n> = (props) => {\n return (\n \n {props.children}\n {(props.footerStyle === undefined || props.footerStyle === FooterStyle.standard) && (\n \n )}\n {props.footerStyle === FooterStyle.minimal && }\n \n );\n};\n\nexport const PageSection = styled.div<{\n noBorder?: boolean;\n noPadding?: boolean;\n centered?: boolean;\n customPadding?: string;\n}>`\n padding: ${(props) =>\n props.customPadding ? props.customPadding : props.noPadding ? '0px 40px' : '20px 40px'};\n border-bottom: ${(props) => (props.noBorder ? '0' : '1px solid #f8f8f8')};\n ${(props) =>\n !props.centered\n ? ``\n : `\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n `}\n\n h2 {\n color: #666666;\n }\n`;\n","import * as React from 'react';\n\nimport styled from 'styled-components';\nimport { IoCheckmarkSharp } from 'react-icons/io5';\n\nconst CoverageItemContainer = styled.div`\n display: flex;\n flex-direction: row;\n width: 100%;\n max-width: calc(50% - 5px);\n\n @media (max-width: 520px) {\n max-width: 100%;\n }\n`;\n\nconst CoverageItemCheckboxContainer = styled.div`\n padding-right: 5px;\n`;\n\nconst CoverageItemDetailsContainer = styled.div`\n flex-direction: column;\n`;\n\nconst CoverageItemTitle = styled.div`\n font-weight: 600;\n padding-bottom: 5px;\n`;\n\nconst CoverageItemDescription = styled.div`\n color: #999999;\n font-size: 0.8em;\n`;\n\nconst CoverageItemCheckbox = styled.div`\n padding-right: 5px;\n color: #0ea5e9;\n font-size: 1.5em;\n`;\n\nexport const CoverageItem: React.FunctionComponent<\n React.PropsWithChildren<{\n title: string;\n description: string;\n icon?: JSX.Element;\n iconColor?: string;\n }>\n> = (props) => (\n \n \n \n {props.icon || }\n \n \n \n {props.title}\n \n {props.description}\n \n \n \n);\n\nconst CoveragePageSectionContainer = styled.div`\n padding: 18px 0px;\n flex: 1 1 0;\n`;\n\nconst CoveragePageSectionTitle = styled.div<{ textColor?: string }>`\n padding: 0px 0px 18px 0px;\n width: 100%;\n\n span {\n font-weight: 600;\n font-size: 0.8em;\n color: ${(props) => props.textColor || '#999999'};\n text-transform: uppercase;\n display: flex;\n align-items: center;\n width: 100%;\n gap: 0.5em;\n\n &::after {\n content: '';\n background-color: ${(props) => props.textColor || '#999999'};\n flex-grow: 1;\n height: 1px;\n }\n }\n`;\n\nconst CoveragePageSectionContent = styled.div`\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n gap: 24px 10px;\n`;\n\nexport const CoveragePageSection: React.FunctionComponent<\n React.PropsWithChildren<{ title?: string; color?: string }>\n> = (props) => (\n \n {props.title && (\n \n {props.title}\n \n )}\n {props.children}\n \n);\n","import { GraphQLErrors } from '@apollo/client/errors';\nimport { ValidationError } from '@oysterjs/types';\n\nexport enum ErrorCode {\n unknown = '',\n unsupportedGeo = 'unsupported_geo',\n riskRejected = 'risk_rejected',\n alreadySubmitted = 'already_submitted',\n submissionFailed = 'submission_failed'\n}\n\nexport enum ErrorType {\n unknown = '',\n\n networkError = 'js.fetch.network_error',\n unknownApiError = 'js.api.unknown_error',\n\n validationError = 'validation_error',\n processingError = 'processing_error',\n underwritingError = 'underwriting_error',\n preconditionFailed = 'precondition_failed'\n}\n\nexport interface WrappedErrorOptions {\n code: ErrorCode;\n type: ErrorType;\n details?: string;\n metadata?: Record;\n cause?: WrappedError | Error;\n}\n\nexport class WrappedError extends Error {\n constructor(\n message: string,\n public opts: WrappedErrorOptions = { code: ErrorCode.unknown, type: ErrorType.unknown }\n ) {\n super(message);\n this.name = 'WrappedError';\n }\n\n type = () => {\n return this.opts.type;\n };\n\n code = () => {\n return this.opts.code;\n };\n\n details = () => {\n return this.opts.details;\n };\n\n cause = () => {\n return this.opts.cause;\n };\n\n metadata = () => {\n return this.opts.metadata || {};\n };\n\n getValidationError = () => {\n return {\n Field: this.opts.metadata?.Field || '',\n SubField: this.opts.metadata?.SubField || '',\n Message: this.message\n };\n };\n\n getGraphQLSchemaValidationError = () => {\n return {\n field: this.opts.metadata?.Field || '',\n subField: this.opts.metadata?.SubField || '',\n message: this.message\n };\n };\n\n // Figure out how to type this better\n // eslint-disable-next-line\n static fromApiError(err: any): WrappedError {\n const x = new WrappedError(err.Message, {\n code: err.Code || ErrorCode.unknown,\n type: err.Type || ErrorType.unknown,\n metadata: {\n Field: err.Field,\n SubField: err.SubField,\n RequestID: err.RequestID\n }\n });\n return x;\n }\n\n static fromValidationError(validationError: ValidationError): WrappedError {\n return new WrappedError(validationError.Message, {\n code: ErrorCode.unknown,\n type: ErrorType.validationError,\n metadata: {\n Field: validationError.Field,\n SubField: validationError.SubField || ''\n }\n });\n }\n\n static fromGraphQLError(errors: GraphQLErrors): WrappedError {\n return new WrappedError(errors.join(''), {\n code: ErrorCode.unknown,\n type: ErrorType.networkError\n });\n }\n\n // Figure out how to type this better\n // eslint-disable-next-line\n static asWrappedError(err: any): WrappedError {\n // TODO: this does not yet handle converting non-WrappedErrors\n // to WrappedError, as Javascript is weird about `instanceof`\n // mixed with catch blocks.\n return err;\n }\n}\n","import { getToken, resetToken } from '@oysterjs/core/auth';\nimport config from '@oysterjs/core/config';\nimport { ErrorCode, ErrorType, WrappedError } from '@oysterjs/core/errors';\n\nexport const getEncodedQueryString = (m: Record): string => {\n const params = new URLSearchParams();\n Object.entries(m).forEach(([key, value]) => {\n if (value) {\n params.set(key, value.toString());\n }\n });\n\n return params.toString();\n};\n\ninterface RequestOpts extends RequestInit {\n redirectUrl?: string;\n disableUnauthorizedRedirect?: boolean;\n}\n\nexport const Get = (path: RequestInfo, init?: RequestOpts) =>\n request(path, undefined, { ...init, method: 'GET' });\n\nexport const Post = (path: RequestInfo, json?: unknown, opts?: RequestOpts) =>\n request(path, json ? JSON.stringify(json) : undefined, { ...opts, method: 'POST' });\n\nexport const Put = (path: RequestInfo, json?: unknown, opts?: RequestOpts) =>\n request(path, json ? JSON.stringify(json) : undefined, { ...opts, method: 'PUT' });\n\nexport const Delete = (path: RequestInfo, json?: unknown, opts?: RequestOpts) =>\n request(path, json ? JSON.stringify(json) : undefined, { ...opts, method: 'DELETE' });\n\nconst request = (path: RequestInfo, json: string | undefined, opts: RequestOpts): Promise =>\n fetch(config().backendBaseUrl.api + path, {\n ...opts,\n mode: 'cors',\n credentials: 'include',\n headers: {\n ...(json ? { 'Content-Type': 'application/json' } : {}),\n ...(getToken() ? { Authorization: `Bearer ${getToken()}` } : {}),\n ...opts.headers\n },\n body: opts.body || json\n })\n .catch((err) => {\n throw new WrappedError('Error performing network request', {\n code: ErrorCode.unknown,\n type: ErrorType.networkError,\n details: `Error performing ${opts.method} ${path}`,\n cause: err\n });\n })\n .then((res) =>\n res.json().then((data) => {\n if (res.status < 300 && data) {\n return data;\n }\n\n if (!opts.disableUnauthorizedRedirect && res.status === 401) {\n resetToken(opts.redirectUrl);\n return data;\n }\n\n if (data.Error) {\n throw WrappedError.fromApiError(data.Error);\n }\n\n throw new WrappedError(`An unknown error with status ${res.status} occurred`, {\n type: ErrorType.unknownApiError,\n code: ErrorCode.unknown,\n details: data.toString()\n });\n })\n );\n","import { getToken, resetToken } from '@oysterjs/core/auth';\nimport { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client';\nimport { removeTypenameFromVariables } from '@apollo/client/link/remove-typename';\nimport {\n DeepPartial,\n Merchant,\n MerchantUser,\n MerchantIntegration,\n ReferralLinkIntegration,\n PolicyTableValues,\n MerchantIntegrationType,\n MerchantRentalConfiguration,\n RentalWaiver,\n WaiverEntry,\n RentalAsset,\n RentalBooking,\n RentalClaim,\n AttachmentFile,\n Transaction,\n UserReferral,\n MerchantRentalConfigurationDetails,\n Insured,\n PublicMerchantRentalConfiguration\n} from '@oysterjs/types';\nimport { Delete, Get, getEncodedQueryString, Post, Put } from './base';\nimport config from '../config';\n\nexport const getMerchantGraphQLClient = () => {\n const removeTypenameLink = removeTypenameFromVariables();\n const link = from([\n removeTypenameLink,\n createHttpLink({\n uri: `${config().backendBaseUrl.api}/merchant/graphql/query`,\n credentials: 'include',\n headers: {\n ...(getToken() ? { Authorization: `Bearer ${getToken()}` } : {})\n }\n })\n ]);\n return new ApolloClient({\n cache: new InMemoryCache(),\n link\n });\n};\n\nexport const createMerchant = (data: {\n Merchant: DeepPartial;\n MerchantUser: Partial;\n AccessCode: string;\n}) => Post('/merchant', data);\n\nexport const merchantUserSignInInit = (email: string, redirect?: string) =>\n Post(\n '/merchant/user/signin/init',\n { Email: email, Redirect: redirect },\n { disableUnauthorizedRedirect: true }\n );\n\nexport const merchantUserSignInComplete = (email: string, code: string) =>\n Post<{ Token: string; MerchantUser: MerchantUser }>(\n '/merchant/user/signin/complete',\n { Email: email, LoginCode: code },\n { disableUnauthorizedRedirect: true }\n );\n\nexport const merchantUserSignOut = () =>\n Post('/merchant/user/signout', { disableUnauthorizedRedirect: true });\n\nexport const getMerchantAccount = (redirectUrl?: string) =>\n Get<{\n Merchant: Merchant;\n MerchantUser: MerchantUser;\n }>('/merchant', { redirectUrl });\n\nexport const getMerchantIntegrations = (redirectUrl?: string) =>\n Get<{\n ApiKey: string;\n Integrations: MerchantIntegration[];\n }>('/merchant/integration', { redirectUrl });\n\nexport const updateMerchantIntegration = (integration: MerchantIntegration) =>\n Put<{ Integration: MerchantIntegration }>(`/merchant/integration/${integration.ID}`, {\n Integration: integration\n });\n\nexport const updateMerchantAccount = (data: { Merchant: DeepPartial }) =>\n Put<{ Merchant: Merchant }>('/merchant', { Merchant: data.Merchant });\n\nexport const linkMerchantWithCheckfront = (\n _: string,\n integrationData: string,\n redirectUrl: string\n) => {\n if (!getToken()) {\n resetToken(redirectUrl);\n return Promise.resolve();\n } else {\n return Post(\n '/merchant/link-integration',\n {\n Type: 'Checkfront',\n IntegrationData: integrationData\n },\n { redirectUrl }\n );\n }\n};\n\nexport const requestCheckfront = () =>\n Get<{\n Integration: MerchantIntegration;\n }>('/merchant/integration/checkfront').then((res) => res.Integration);\n\nexport const requestQRCode = () =>\n Get<{\n Integration: MerchantIntegration;\n QRCode: string;\n }>('/merchant/integration/QRCode');\n\nexport const requestQRCodePdf = () =>\n Get<{ DocumentUrl: string; DocumentZip: string }>('/merchant/integration/QRCode/pdf');\n\nexport const getMerchantReferrals = (start: Date, end: Date) =>\n Get<{ Referrals: PolicyTableValues[] }>(\n `/merchant/referrals?startTime=${start.toISOString()}&endTime=${end.toISOString()}`\n );\n\nexport const getMerchantTransactions = (start: Date, end: Date) =>\n Get<{ Transactions: Transaction[] }>(\n `/merchant/transactions?startTime=${start.toISOString()}&endTime=${end.toISOString()}`\n );\n\nexport const getMerchantLink = (\n integrationType?: MerchantIntegrationType,\n externalID?: string,\n integrationID?: string\n) =>\n Get(\n `/merchant/referrallink?${getEncodedQueryString({\n externalID,\n integrationID,\n integrationType\n })}`\n );\n\nexport const getMerchantUsers = () => Get<{ Users: MerchantUser[] }>('/merchant/users');\nexport const createMerchantUser = (user: Partial) =>\n Post('/merchant/users', { MerchantUser: user });\n\n// RENTAL APIs\n\nexport const getMerchantRentalConfiguration = (): Promise<{\n Configuration?: MerchantRentalConfiguration;\n ReferralLink?: string;\n QRCodeBase64?: string;\n}> => Get('/merchant/rental');\n\nexport const getPublicMerchantRentalConfiguration = (\n integrationId: string\n): Promise<{\n Configuration: PublicMerchantRentalConfiguration;\n}> => Get('/merchant/rental/public', { headers: { 'X-Merchant-Integration-Id': integrationId } });\n\nexport const updateMerchantRentalConfiguration = (\n settings: DeepPartial\n): Promise<{\n Configuration: MerchantRentalConfiguration;\n}> => Put('/merchant/rental', { Settings: settings });\n\nexport const getMerchantRentalPaymentSetup = (): Promise<{\n PaymentMethod?: { BankName: string; LastFour: string };\n SetupIntentClientSecret?: string;\n}> => Get('/merchant/rental/payment');\n\nexport const getRentalDocuments = () =>\n Get<{ Metadata: AttachmentFile[] }>(`/merchant/rental/waiverdocuments`).then(\n (d) => d.Metadata || []\n );\n\nexport const uploadRentalDocuments = (files: File[]) => {\n const form = new FormData();\n files.forEach((file) => form.append('files[]', file));\n return Post<{ Metadata: AttachmentFile[] }>(`/merchant/rental/waiverdocuments`, undefined, {\n body: form\n }).then((d) => d.Metadata || []);\n};\n\nexport const deleteRentalDocument = (id: string) =>\n Delete<{ Metadata: AttachmentFile[] }>(`/merchant/rental/waiverdocuments/${id}`).then(\n (d) => d.Metadata || []\n );\n\nexport const getRentalWaivers = (): Promise =>\n Get<{\n Entries: WaiverEntry[];\n }>('/merchant/rental/waivers').then((d) => d.Entries);\n\nexport const getRentalWaiver = (waiverId: string): Promise =>\n Get<{\n Entry: WaiverEntry;\n }>(`/merchant/rental/waiver/${waiverId}`).then((d) => d.Entry);\n\nexport const getRentalBooking = (bookingId: string): Promise =>\n Get<{\n Entry: WaiverEntry;\n }>(`/merchant/rental/booking/${bookingId}`).then((d) => d.Entry);\n\nexport const createRentalBooking = (\n booking: RentalBooking,\n integrationId?: string\n): Promise<{ UpdatedBooking: RentalBooking; UpdatedWaiver?: RentalWaiver }> =>\n Post<{\n Booking: RentalBooking;\n Waiver: RentalWaiver;\n }>(\n '/merchant/rental/booking',\n { Booking: booking },\n { headers: { 'X-Merchant-Integration-Id': integrationId || '' } }\n ).then((d) => ({\n UpdatedBooking: d.Booking,\n UpdatedWaiver: d.Waiver\n }));\n\nexport const updateRentalBooking = (\n booking: RentalBooking,\n integrationId?: string\n): Promise<{ UpdatedBooking: RentalBooking; UpdatedWaiver?: RentalWaiver }> =>\n Put<{\n Booking: RentalBooking;\n Waiver: RentalWaiver;\n }>(\n `/merchant/rental/booking/${booking.ID}`,\n { Booking: booking },\n { headers: { 'X-Merchant-Integration-Id': integrationId || '' } }\n ).then((d) => ({\n UpdatedBooking: d.Booking,\n UpdatedWaiver: d.Waiver\n }));\n\nexport const getWaiverPricing = (\n booking: RentalBooking,\n waiver: RentalWaiver,\n integrationId?: string\n): Promise =>\n Post<{\n Waiver: RentalWaiver;\n }>(\n '/merchant/rental/waiver/price',\n { Booking: booking, Waiver: waiver },\n { headers: { 'X-Merchant-Integration-Id': integrationId || '' } }\n ).then((d) => d.Waiver);\n\nexport const createRentalWaiver = (\n booking: RentalBooking,\n waiver: RentalWaiver,\n sendEmail: boolean,\n integrationId?: string\n): Promise<{ UpdatedBooking: RentalBooking; UpdatedWaiver: RentalWaiver }> =>\n Post<{\n Booking: RentalBooking;\n Waiver: RentalWaiver;\n }>(\n '/merchant/rental/waiver',\n { Booking: booking, Waiver: waiver, SendEmail: sendEmail },\n { headers: { 'X-Merchant-Integration-Id': integrationId || '' } }\n ).then((d) => ({\n UpdatedBooking: d.Booking,\n UpdatedWaiver: d.Waiver\n }));\n\nexport const updateRentalWaiver = (\n booking: RentalBooking,\n waiver: RentalWaiver,\n sendEmail: boolean,\n integrationId?: string\n): Promise<{ UpdatedBooking: RentalBooking; UpdatedWaiver: RentalWaiver }> =>\n Put<{\n Booking: RentalBooking;\n Waiver: RentalWaiver;\n }>(\n '/merchant/rental/waiver',\n { Booking: booking, Waiver: waiver, SendEmail: sendEmail },\n { headers: { 'X-Merchant-Integration-Id': integrationId || '' } }\n ).then((d) => ({\n UpdatedBooking: d.Booking,\n UpdatedWaiver: d.Waiver\n }));\n\nexport const createMerchantRentalAsset = (asset: DeepPartial) =>\n Post<{ Asset: RentalAsset }>(`/merchant/rental/assets`, { Asset: asset }).then((r) => r.Asset);\n\nexport const deleteMerchantRentalAsset = (assetId: string) =>\n Delete(`/merchant/rental/assets/${assetId}`);\n\nexport const addRentalAssetSerialNumber = (\n assetId: string,\n serialNumber: string,\n integrationId?: string\n) =>\n Put<{ Asset: RentalAsset }>(\n `/merchant/rental/assets/${assetId}/serialnumber`,\n {\n SerialNumber: serialNumber\n },\n { headers: { 'X-Merchant-Integration-Id': integrationId || '' } }\n ).then((r) => r.Asset);\n\nexport const getRentalWaiverPaymentSession = (waiverId: string): Promise =>\n Post<{ StripeClientSecret: string }>(`/merchant/rental/waiver/${waiverId}/payment`).then((d) => {\n return d.StripeClientSecret;\n });\n\nexport const getRentalWaiverAgreementInformation = (\n waiverId: string\n): Promise<{\n SignedDate: Date;\n CustomerName: string;\n MerchantName: string;\n RentalBookingDate: Date;\n RentalBookingDurationInDays: number;\n}> => Post(`/merchant/rental/waiver/${waiverId}/agreement`);\n\nexport const completeRentalBooking = (\n bookingId: string,\n signatureData: string,\n insured?: DeepPartial\n): Promise =>\n Post<{\n Booking: RentalBooking;\n }>(`/merchant/rental/booking/${bookingId}/complete`, {\n Insured: insured,\n SignatureData: signatureData\n }).then((d) => d.Booking);\n\nexport const completeRentalWaiver = (\n waiverId: string,\n signatureData: string,\n insured?: DeepPartial\n): Promise =>\n Post<{\n Waiver: RentalWaiver;\n }>(`/merchant/rental/waiver/${waiverId}/complete`, {\n Insured: insured,\n SignatureData: signatureData\n }).then((d) => d.Waiver);\n\nexport const cancelBookingRenewal = (bookingId: string): Promise =>\n Post<{\n Booking: RentalBooking;\n }>(`/merchant/rental/booking/${bookingId}/cancel-renew`).then((d) => d.Booking);\n\nexport const getMerchantRentalAssets = (integrationId?: string): Promise =>\n Get<{\n Assets?: RentalAsset[];\n }>('/merchant/rental/assets', {\n headers: { 'X-Merchant-Integration-Id': integrationId || '' }\n }).then((d) => d.Assets || []);\n\nexport const getRentalBookingFiles = (id: string) =>\n Get<{\n Files: AttachmentFile[] | null;\n }>(`/merchant/rental/booking/${id}/files`).then((res) => res.Files);\n\nexport const getRentalClaimByWaiverId = (\n waiverId: string\n): Promise<{ Entry: WaiverEntry; Claim?: RentalClaim; Attachments: AttachmentFile[] }> =>\n Get<{\n Entry: WaiverEntry;\n Claim?: RentalClaim;\n Attachments: AttachmentFile[];\n }>(`/merchant/rental/waiver/${waiverId}/claim`);\n\nexport const getRentalClaim = (\n id: string\n): Promise<{ Entry: WaiverEntry; Claim: RentalClaim; Attachments: AttachmentFile[] }> =>\n Get<{\n Entry: WaiverEntry;\n Claim: RentalClaim;\n Attachments: AttachmentFile[];\n }>(`/merchant/rental/claim/${id}`);\n\nexport const createRentalClaim = (claim: RentalClaim): Promise =>\n Post<{ UpdatedClaim: RentalClaim }>(`/merchant/rental/claim`, {\n Claim: claim\n }).then((res) => res.UpdatedClaim);\n\nexport const updateRentalClaim = (id: string, claim: RentalClaim): Promise =>\n Put<{ UpdatedClaim: RentalClaim }>(`/merchant/rental/claim/${id}`, {\n Claim: claim\n }).then((res) => res.UpdatedClaim);\n\nexport const uploadClaimAttachments = (claimId: string, fileRole: string, files: File[]) => {\n const form = new FormData();\n files.forEach((file) => form.append('files[]', file));\n form.append('FileRole', fileRole);\n return Post<{ Metadata: AttachmentFile[] }>(\n `/merchant/rental/claim/${claimId}/attachment`,\n undefined,\n {\n body: form\n }\n ).then((d) => d.Metadata || []);\n};\n\nexport const getMerchantReferralList = () =>\n Get<{ Referrals: UserReferral[] }>('/merchant/referral/list').then((d) => d.Referrals || []);\n","import { Cookies } from 'react-cookie';\nimport { ReferralLinkIntegration } from '@oysterjs/types';\n\nconst ATTRIBUTION_COOKIE = 'oyster_attribution';\n\nexport enum CookieParameters {\n AttributionType = 'type',\n MerchantIntegrationId = 'merchant_integration_id',\n UtmSource = 'utm_source',\n UtmCampaign = 'utm_campaign',\n UtmMedium = 'utm_medium',\n UtmTerm = 'utm_term',\n GoogleId = 'gclid',\n FacebookId = 'fbclid',\n PageHistory = '_oh'\n}\n\nenum AttributionCookieType {\n Merchant = 'merchant',\n Marketing = 'marketing',\n Direct = 'direct'\n}\n\nexport const setMerchantAttribution = (integration: ReferralLinkIntegration) => {\n const cookies = new Cookies();\n const params = new URLSearchParams({\n [CookieParameters.AttributionType]: AttributionCookieType.Merchant,\n [CookieParameters.MerchantIntegrationId]: integration.IntegrationID\n });\n cookies.set(ATTRIBUTION_COOKIE, params.toString(), { path: '/' });\n};\n","export const Spinner = ({\n color,\n size,\n centerHorizontal\n}: {\n color?: string;\n size?: number;\n centerHorizontal?: boolean;\n}): JSX.Element => (\n \n \n \n \n \n);\n","import styled, { keyframes } from 'styled-components';\n\nexport const TextSkeleton = styled.span`\n display: inline;\n margin: 0px 5px;\n border-radius: 5px;\n padding: 0px 2px;\n background: rgba(255, 255, 255, 0.3);\n animation: ${keyframes`\n 0% {\n background: rgba(255, 255, 255, 0.3);\n }\n 25% {\n background: rgba(255, 255, 255, 0.45);\n }\n 100% {\n background: rgba(255, 255, 255, 0.3);\n }\n `} 2s infinite;\n color: transparent;\n font-weight: bold;\n word-break: break-all;\n`;\n","import React from 'react';\nimport styled from 'styled-components';\nimport { useId } from 'react-id-generator';\n\nexport const FormContainer = styled.form`\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: 100%;\n`;\n\nexport const FormRowContainer = styled.div<{\n breakMobile?: boolean;\n alignItems?: string;\n singleItem?: boolean;\n}>`\n display: flex;\n flex-direction: row;\n align-items: ${(props) => (props.alignItems ? props.alignItems : 'normal')};\n gap: 16px;\n width: 100%;\n max-width: ${(props) => (props.singleItem ? 'calc(50% - 8px)' : '100%')};\n\n @media (max-width: 600px) {\n max-width: 100%;\n flex-direction: ${(props) => (props.breakMobile ? 'column' : 'row')};\n }\n`;\n\nconst FormRowHeaderContainer = styled.div<{ paddingTop?: string }>`\n padding-top: ${(props) => (props.paddingTop ? props.paddingTop : '24px')};\n`;\n\nconst FormRowHeaderDescription = styled.div`\n color: #999999;\n font-size: 0.9em;\n padding-top: 4px;\n`;\n\nconst FormRowHeaderTitle = styled.div`\n font-size: 1.1em;\n font-weight: 500;\n`;\n\nconst FormRowError = styled.div`\n font-size: 0.8em;\n color: #d1344b;\n`;\n\ninterface FormRowProps {\n error?: string | false;\n breakMobile?: boolean;\n alignItems?: string;\n singleItem?: boolean;\n}\n\nexport const FormRow: React.FunctionComponent<\n React.PropsWithChildren & FormRowProps>\n> = (props) => (\n <>\n {props.children}\n {props.error && {props.error}}\n \n);\n\ninterface FormRowHeaderProps {\n title?: string;\n description?: string;\n paddingTop?: string;\n}\n\nexport const FormRowHeader: React.FunctionComponent> = (\n props\n) => (\n \n {props.title && {props.title}}\n {props.description && {props.description}}\n \n);\n\nconst FormColumnContainer = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1 1 0;\n`;\n\nconst FormColumnTitle = styled.label`\n font-weight: 500;\n`;\n\nconst FormColumnDescription = styled.div`\n padding-bottom: 8px;\n font-size: 0.8em;\n color: #666666;\n`;\n\nconst FormColumnContents = styled.div``;\n\n// Temporary enum to distinguish the desired style\n// on the merchant form vs. the consumer forms. we'll\n// unify these styles once we have a design language.\nexport enum FormColumnStyle {\n merchant = 'merchant'\n}\n\ninterface FormColumnProps {\n title?: string;\n description?: string;\n label?: string;\n optional?: boolean;\n formColumnStyle?: FormColumnStyle;\n}\n\nexport const FormColumn: React.FunctionComponent<\n React.PropsWithChildren & FormColumnProps>\n> = (props) => {\n const [id] = useId();\n\n return (\n \n \n {props.title || props.label}\n {props.optional && (opt.)}\n \n {props.description && {props.description}}\n \n {React.Children.map(props.children, (child) =>\n React.isValidElement(child) ? React.cloneElement(child as JSX.Element, { id }) : child\n )}\n \n \n );\n};\n","import React from 'react';\nimport styled from 'styled-components';\nimport { NumericFormat, OnValueChange } from 'react-number-format';\n\nexport const ErrorDisplay = styled.div`\n font-size: 0.8em;\n margin-top: 5px;\n color: #d1344b;\n`;\n\nexport const TextInputComponent = styled.input<{\n error?: string | null | false | true;\n currency?: boolean | false;\n}>`\n border: 0;\n outline: none;\n\n border-radius: 20px;\n border: ${(props) => (props.error ? '2px solid #d1344b' : '2px solid #e8e8e8')};\n box-sizing: border-box;\n font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n font-size: 1em;\n padding: 8px 16px;\n\n padding-left: ${(props) => props.currency && '30px'};\n\n width: 100%;\n\n transition: 0.15s all;\n\n &:focus {\n border: 2px solid #0ea5e9;\n }\n\n &:focus + .suggestions-container {\n display: block;\n }\n`;\n\nexport const TextInput = React.forwardRef(\n (\n props: React.AllHTMLAttributes & {\n error?: string | null | false | true;\n currency?: boolean | false;\n },\n ref: React.Ref\n ) => (\n <>\n
\n {props.currency && (\n \n $\n \n )}\n \n {props.error && props.error !== true && {props.error}}\n
\n \n )\n);\n\nexport const CurrencyComponent = styled(NumericFormat)<{\n error?: string | null | false | true;\n currency?: boolean | false;\n}>`\n border: 0;\n outline: none;\n\n border-radius: 20px;\n border: ${(props) => (props.error ? '2px solid #d1344b' : '2px solid #e8e8e8')};\n box-sizing: border-box;\n font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n font-size: 1em;\n padding: 8px 16px;\n\n width: 100%;\n\n transition: 0.15s all;\n\n &:focus {\n border: 2px solid #0ea5e9;\n }\n\n &:focus + .suggestions-container {\n display: block;\n }\n`;\n\nexport const CurrencyInput = (\n props: React.AllHTMLAttributes & {\n error?: string | null | false | true;\n currency?: boolean | false;\n value?: string | number;\n onValueChange?: OnValueChange;\n style?: React.CSSProperties;\n }\n) => {\n return (\n
\n \n {props.error && props.error !== true && {props.error}}\n
\n );\n};\n\nconst SuggestionsContainer = styled.div`\n position: absolute;\n display: none;\n box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.25);\n box-sizing: border-box;\n border-radius: 8px;\n z-index: 100;\n background: white;\n font-size: 0.9em;\n\n &:hover {\n display: block;\n }\n\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n ul li {\n padding: 10px 20px;\n\n &:first-child {\n border-top-left-radius: 8px;\n border-top-right-radius: 8px;\n }\n\n &:last-child {\n border-bottom-left-radius: 8px;\n border-bottom-right-radius: 8px;\n }\n\n &:hover {\n background: #0ea5e9;\n color: white;\n cursor: pointer;\n }\n }\n`;\n\nconst Suggestions = (props: {\n suggestions: string[];\n onSelect?: (suggestion: string, index: number) => void;\n}) => (\n \n
    \n {props.suggestions.map((s, i) => (\n
  • (props.onSelect ? props.onSelect(s, i) : null)}>\n {s}\n
  • \n ))}\n
\n
\n);\n\ninterface AutocompleteTextInputProps {\n suggestions: string[];\n id?: string;\n value?: string;\n error?: boolean;\n disabled?: boolean;\n onChange?: (value: string) => void;\n onSelectSuggestion?: (suggestion: string, index: number) => void;\n}\n\nexport const AutocompleteTextInput = (props: AutocompleteTextInputProps): JSX.Element => {\n const [selectedSuggestion, setSelectedSuggestion] = React.useState(false);\n return (\n
\n {\n setSelectedSuggestion(false);\n props.onChange?.(e.currentTarget.value);\n }}\n disabled={props.disabled}\n />\n {props.suggestions.length > 0 && !selectedSuggestion && (\n {\n setSelectedSuggestion(true);\n props.onSelectSuggestion?.(suggestion, index);\n }}\n />\n )}\n
\n );\n};\nexport const TextAreaInputComponent = styled.textarea<{ error?: string | null | false }>`\n border: 0;\n outline: none;\n\n border-radius: 20px;\n border: ${(props) => (props.error ? '2px solid #d1344b' : '2px solid #e8e8e8')};\n box-sizing: border-box;\n font-family: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n font-size: 1em;\n padding: 12px 16px;\n\n width: 100%;\n\n transition: 0.15s all;\n\n &:focus {\n border: 2px solid #0ea5e9;\n }\n`;\n\nexport const TextAreaInput: React.FunctionComponent<\n React.AllHTMLAttributes & { error?: string | null | false }\n> = (props) => (\n <>\n \n {props.error && {props.error}}\n \n);\n","import * as React from 'react';\nimport styled from 'styled-components';\nimport { ErrorDisplay, TextInputComponent } from './text';\nimport { IoAdd } from 'react-icons/io5';\nimport { Spinner } from '../Spinner';\n\nconst SelectInput = styled.select<{ error?: string | false | null }>`\n border: 0;\n outline: none;\n appearance: none;\n background: white;\n\n border-radius: 20px;\n border: ${(props) => (props.error ? '2px solid #d1344b' : '2px solid #e8e8e8')};\n box-sizing: border-box;\n font-size: 1em;\n padding: 8px 40px 8px 20px;\n\n width: 100%;\n\n transition: 0.15s all;\n\n &:focus {\n border: 2px solid #0ea5e9;\n }\n\n ::placeholder {\n color: #aaaaaa;\n }\n\n font-family: 'Inter', 'Helvetica Neue', 'Arial', sans-serif;\n`;\n\nconst Carat = styled.div`\n display: block;\n position: absolute;\n cursor: pointer;\n right: 1rem;\n top: 50%;\n margin-top: -1px;\n width: 0;\n height: 0;\n border-top: 5px solid #999;\n border-right: 5px solid transparent;\n border-left: 5px solid transparent;\n pointer-events: none;\n`;\n\nexport interface SelectProps {\n initialSelected?: string; // denotes uncontrolled\n selected?: string; // denotes controlled\n disabled?: boolean;\n style?: React.CSSProperties;\n\n error?: string | false | null;\n options?: { value: string; displayValue?: string }[];\n onChange?: (value: string) => void;\n}\n\nexport const Select = (\n props: React.AllHTMLAttributes & SelectProps\n): JSX.Element => {\n return (\n
\n
\n {\n e.stopPropagation();\n }}\n onChange={(e) => {\n e.stopPropagation();\n if (props.onChange) {\n props.onChange(e.currentTarget.value);\n }\n }}\n >\n {(props.options || []).map((option) => (\n \n ))}\n \n \n
\n {props.error && {props.error}}\n
\n );\n};\n\nexport const UnstyledSelect = (props: SelectProps): JSX.Element => {\n const [selected, setSelected] = React.useState(props.selected || props.initialSelected);\n\n React.useEffect(() => {\n setSelected(props.selected);\n }, [props.selected]);\n\n return (\n {\n e.stopPropagation();\n }}\n onChange={(e) => {\n e.stopPropagation();\n if (!props.selected) {\n setSelected(e.currentTarget.value);\n }\n if (props.onChange) {\n props.onChange(e.currentTarget.value);\n }\n }}\n value={selected}\n disabled={props.disabled}\n >\n {(props.options || []).map((option) => (\n \n ))}\n \n );\n};\n\nconst SearchableSelectOptionsContainer = styled.div`\n position: absolute;\n display: none;\n box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.25);\n box-sizing: border-box;\n border-radius: 8px;\n margin-top: 4px;\n z-index: 100;\n background: white;\n width: 100%;\n\n &:hover {\n display: block;\n }\n\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n ul li {\n padding: 10px 20px;\n font-size: 0.9em;\n\n &:first-child {\n border-top-left-radius: 8px;\n border-top-right-radius: 8px;\n }\n\n &:last-child {\n border-bottom-left-radius: 8px;\n border-bottom-right-radius: 8px;\n }\n\n &:hover {\n background: #0ea5e9;\n color: white;\n cursor: pointer;\n\n span.highlighted {\n background: none;\n font-weight: normal;\n }\n }\n }\n\n li.add-item {\n border-top: 2px solid #f2f2f2;\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 0.9em;\n font-weight: 600;\n\n &.loading {\n background: #f8f8f8;\n cursor: wait;\n color: #666666;\n }\n }\n\n span.highlighted {\n background: yellow;\n font-weight: 600;\n }\n`;\n\nconst SearchableSelectOptions = (props: {\n options: string[];\n inputText: string;\n onSelect: (option: string) => void;\n onAdd: (option: string) => Promise;\n}) => {\n const [loading, setLoading] = React.useState(false);\n\n const handleAddOption = async () => {\n if (loading) {\n return;\n }\n\n try {\n setLoading(true);\n await props.onAdd(props.inputText);\n } finally {\n setLoading(false);\n }\n };\n\n const caseInsensitiveIndexOf = (s: string, sub: string) =>\n s.toLowerCase().indexOf(sub.toLowerCase());\n\n // Ranked options are the options to display in the dropdown. This is filtered\n // and ordered in an intuitive way for the user.\n const rankedOptions = props.options\n // First, only show options that contain the input string as a complete substring\n // unless the input string is empty, in which case show all opions.\n .filter((option) => !props.inputText || caseInsensitiveIndexOf(option, props.inputText) !== -1)\n // Next, build the sort key for each option. First, sort by the position of the\n // first complete substring match (prefer options that have the input text earlier\n // in the option rather than later). If the positions are the same, break the tie\n // by sorting based on the index option, keeping them in the original order (this is\n // also known as a stable sort). The final element is the actual option to render.\n .map((s, i): [number, number, string] => [caseInsensitiveIndexOf(s, props.inputText), i, s])\n // Generic sort comparator that sorts ascending by each corresponding element in the\n // sort key, checking subsequent elements in the key when prior elements are equal.\n .sort((a, b) => {\n for (let i = 0; i < a.length && i < b.length; i++) {\n if (a[i] !== b[i]) {\n return a[i] < b[i] ? -1 : 1;\n }\n }\n return 0;\n });\n\n return (\n \n
    \n
    \n {rankedOptions.map(([, , option]) => (\n
  • props.onSelect?.(option)}>\n {[...option].map((char, i) => (\n = caseInsensitiveIndexOf(option, props.inputText) &&\n i < caseInsensitiveIndexOf(option, props.inputText) + props.inputText.length\n ? 'highlighted'\n : undefined\n }\n >\n {char}\n \n ))}\n
  • \n ))}\n
    \n {!props.options.some((opt) => opt === props.inputText) && props.inputText != '' && (\n
  • \n {loading && (\n <>\n Adding \"{props.inputText}\"...\n \n )}\n {!loading && (\n <>\n Add \"{props.inputText}\"\n \n )}\n
  • \n )}\n
\n
\n );\n};\n\ninterface SearchableSelectProps {\n options: string[];\n initialValue?: string;\n disabled?: boolean;\n error?: string;\n onChange?: (value: string) => void;\n onAddOption?: (value: string) => Promise;\n onSelectOption?: (value: string) => void;\n}\n\nexport const SearchableSelect = (props: SearchableSelectProps): JSX.Element => {\n const [selectedOption, setSelectedOption] = React.useState(false);\n const [value, setValue] = React.useState(props.initialValue);\n\n React.useEffect(() => {\n setValue(props.initialValue);\n }, [props.initialValue]);\n\n return (\n
\n {\n setSelectedOption(false);\n setValue(e.currentTarget.value.trim());\n props.onChange?.(e.currentTarget.value.trim());\n }}\n onFocus={() => setSelectedOption(false)}\n disabled={props.disabled}\n />\n {!selectedOption && (\n {\n setSelectedOption(true);\n setValue(value);\n props.onSelectOption?.(value);\n }}\n onAdd={async (value: string) => {\n if (!props.onAddOption) {\n return;\n }\n\n await props.onAddOption(value);\n setSelectedOption(true);\n setValue(value);\n }}\n />\n )}\n {props.error && {props.error}}\n
\n );\n};\n","import * as React from 'react';\nimport styled from 'styled-components';\n\nimport { Spinner } from '../Spinner';\n\ninterface Props {\n request: Promise;\n exactlyOnce?: boolean;\n hideSpinner?: boolean;\n inline?: boolean;\n children: (data: T) => JSX.Element | null;\n}\n\nexport const LoadableContainer = styled.div<{ inline?: boolean }>`\n width: 100%;\n box-sizing: border-box;\n ${(props) =>\n props.inline\n ? ''\n : `\n padding: 40px 0px;display: flex;\n flex-direction: row;\n justify-content: center;\n `}\n`;\n\nexport function Loadable(props: Props): JSX.Element | null {\n const [data, setData] = React.useState(null);\n\n React.useEffect(() => {\n if (!props.exactlyOnce || !data) {\n props.request.then(setData);\n }\n }, [props.request]);\n\n if (!data) {\n return props.hideSpinner ? null : (\n \n \n \n );\n }\n\n return props.children(data);\n}\n","import * as React from 'react';\nimport { Link } from 'react-router-dom';\nimport styled from 'styled-components';\n\nimport { Spinner } from '../Spinner';\n\nconst UnstyledLink = styled.a`\n color: inherit;\n text-decoration: inherit;\n\n &:visited {\n color: inherit;\n text-decoration: inherit;\n }\n`;\n\nconst ButtonContainerComponent = styled.div`\n display: flex;\n flex-direction: row;\n gap: 0px 6px;\n\n width: 100%;\n justify-content: ${(props) => (props.center ? 'center' : 'left')};\n`;\n\ninterface ButtonContainerProps {\n center?: boolean;\n}\n\nexport const ButtonContainer = (\n props: React.PropsWithChildren & ButtonContainerProps>\n) => {props.children};\n\nconst ButtonComponent = styled.button<{\n primary?: boolean;\n loading?: boolean;\n}>`\n border: 0;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 5px;\n\n padding: 10px 15px;\n border-radius: 30px;\n user-select: none;\n\n font-size: 0.8em;\n font-weight: 500;\n\n min-width: 100px;\n justify-content: center;\n\n color: ${(props) => (props.primary ? 'white' : '#333333')};\n background: ${(props) => (props.primary ? '#0ea5e9' : '#fafafa')};\n border: ${(props) => (props.primary ? '1px solid transparent' : '1px solid #DADADA')};\n font-family: 'Rubik', 'Helvetica Neue', 'Helvetica', Arial, sans-serif;\n\n opacity: ${(props) => (props.loading || props.disabled ? 0.6 : 1)};\n cursor: ${(props) => (props.loading || props.disabled ? 'default' : 'pointer')};\n\n transition: all 0.15s ease-in-out;\n\n &:active {\n transform: ${(props) => {\n if (props.loading || props.disabled) {\n return 'none';\n }\n return 'translateY(2px)';\n }};\n background: ${(props) => {\n if (props.loading || props.disabled) {\n return props.primary ? '#0ea5e9' : '#fafafa';\n }\n return props.primary ? '#269985' : 'rgb(212, 212, 212)';\n }};\n }\n\n &:first-child {\n margin-left: 0;\n }\n\n &:last-child {\n margin-right: 0;\n }\n`;\n\nconst ButtonDivComponent = styled.div<{\n primary?: boolean;\n loading?: boolean;\n disabled?: boolean;\n}>`\n border: 0;\n\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 5px;\n\n padding: 10px 15px;\n border-radius: 30px;\n user-select: none;\n\n font-size: 0.8em;\n font-weight: 500;\n\n color: ${(props) => (props.primary ? 'white' : '#333333')};\n background: ${(props) => (props.primary ? '#0ea5e9' : '#fafafa')};\n border: ${(props) => (props.primary ? '1px solid transparent' : '1px solid #DADADA')};\n font-family: 'Rubik', 'Helvetica Neue', 'Helvetica', Arial, sans-serif;\n\n opacity: ${(props) => (props.loading || props.disabled ? 0.6 : 1)};\n cursor: ${(props) => (props.loading || props.disabled ? 'default' : 'pointer')};\n\n transition: all 0.15s ease-in-out;\n\n :active {\n transform: translateY(2px);\n background: ${(props) => {\n if (props.loading || props.disabled) {\n return props.primary ? '#0ea5e9' : '#fafafa';\n }\n return props.primary ? '#269985' : 'rgb(212, 212, 212)';\n }};\n }\n\n :first-child {\n margin-left: 0;\n }\n\n :last-child {\n margin-right: 0;\n }\n`;\n\ninterface ButtonProps {\n primary?: boolean;\n loading?: boolean;\n disabled?: boolean;\n icon?: JSX.Element;\n leftIcon?: JSX.Element;\n style?: React.CSSProperties;\n}\n\ninterface LinkProps {\n href: string;\n target?: string;\n onClick?: () => void;\n}\n\nexport const ButtonLink = (props: React.PropsWithChildren) =>\n props.disabled ? (\n \n {selectedAssets.length > 1 && (\n \n )}\n \n \n \n \n {\n const value = e.currentTarget.value;\n onChangeBooking((prev) => ({\n ...prev,\n Details: {\n ...prev?.Details,\n Insured: { ...prev?.Details?.Insured, FirstName: value }\n }\n }));\n }}\n autoComplete=\"given-name\"\n />\n \n \n {\n const value = e.currentTarget.value;\n onChangeBooking((prev) => ({\n ...prev,\n Details: {\n ...prev?.Details,\n Insured: { ...prev?.Details?.Insured, LastName: value }\n }\n }));\n }}\n autoComplete=\"family-name\"\n />\n \n \n \n \n {\n const value = e.currentTarget.value;\n onChangeBooking((prev) => ({\n ...prev,\n Details: {\n ...prev?.Details,\n Insured: { ...prev?.Details?.Insured, Email: value }\n }\n }));\n }}\n inputMode=\"email\"\n autoComplete=\"email\"\n />\n \n \n {\n const value = e.currentTarget.value;\n onChangeBooking((prev) => ({\n ...prev,\n Details: {\n ...prev?.Details,\n Insured: { ...prev?.Details?.Insured, Phone: value }\n }\n }));\n }}\n inputMode=\"tel\"\n autoComplete=\"tel\"\n />\n \n \n {props.rentalConfig.UnifiedWaiverFlowEnabled && (\n \n )}\n {props.rentalConfig.UnifiedWaiverFlowEnabled && (\n [\n a.Value,\n ...(a.Details.AvailableAccessories || []).map((aa) => aa.Value)\n ])\n .reduce((a, c) => a + c, 0),\n Currency: 'usd'\n }}\n waiverPremium={waiverPremium}\n waiverOptedIn={waiverOptedIn}\n setWaiverOptedIn={setWaiverOptedIn}\n />\n )}\n \n \n }\n loading={submitLoading}\n onClick={onCreateOrUpdateWaiver}\n >\n {!props.rentalConfig.UnifiedWaiverFlowEnabled\n ? 'Continue'\n : waiverOptedIn\n ? 'Continue to sign and pay'\n : 'Continue to sign'}\n \n \n \n\n {error && {error}}\n \n );\n};\n\nconst RentalAgreement = (props: { integrationId: string }) => {\n const ref = React.useRef(null);\n\n const url =\n config().backendBaseUrl.statics +\n `/merchant/rental/waiverdocuments?IntegrationID=${props.integrationId}`;\n const embeddedUrl = `https://drive.google.com/viewerng/viewer?embedded=true&url=${encodeURIComponent(\n url\n )}`;\n\n React.useEffect(() => {\n const interval = setInterval(() => {\n if (ref.current) {\n ref.current.src = embeddedUrl;\n }\n }, 3000);\n\n if (ref.current) {\n ref.current.addEventListener('load', () => {\n clearInterval(interval);\n });\n }\n\n return () => clearInterval(interval);\n }, [ref.current]);\n\n return (\n <>\n \n \n