Merged in chore/delete-unused-files (pull request #3346)
chore: Delete unused files * Delete unused files Ignore design-system for now Approved-by: Joakim Jäderberg
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
import { useBookingFlowContext } from "@scandic-hotels/booking-flow/hooks/useBookingFlowContext"
|
|
||||||
|
|
||||||
export function useIsUserLoggedIn() {
|
|
||||||
const { isLoggedIn } = useBookingFlowContext()
|
|
||||||
return isLoggedIn
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
import { Suspense } from "react"
|
|
||||||
|
|
||||||
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
||||||
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
|
|
||||||
|
|
||||||
import Blocks from "@/components/Blocks"
|
|
||||||
import HeaderDynamicContent from "@/components/Headers/DynamicContent"
|
|
||||||
import Hero from "@/components/Hero"
|
|
||||||
import { HeroVideo } from "@/components/HeroVideo"
|
|
||||||
import MeetingPackageWidget from "@/components/MeetingPackageWidget"
|
|
||||||
import Sidebar from "@/components/Sidebar"
|
|
||||||
import SidebarSkeleton from "@/components/Sidebar/SidebarSkeleton"
|
|
||||||
import LinkChips from "@/components/TempDesignSystem/LinkChips"
|
|
||||||
|
|
||||||
import { staticPageVariants } from "./variants"
|
|
||||||
|
|
||||||
import styles from "./staticPage.module.css"
|
|
||||||
|
|
||||||
import type { StaticPageProps } from "./staticPage"
|
|
||||||
|
|
||||||
export default async function StaticPage({
|
|
||||||
content,
|
|
||||||
tracking,
|
|
||||||
pageType,
|
|
||||||
}: StaticPageProps) {
|
|
||||||
const { blocks, hero_image, hero_video, header, meeting_package } = content
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<section className={staticPageVariants({ pageType })}>
|
|
||||||
<header className={styles.header}>
|
|
||||||
<div className={styles.headerContent}>
|
|
||||||
{header ? (
|
|
||||||
<>
|
|
||||||
<div className={styles.headerIntro}>
|
|
||||||
<Typography variant="Title/lg">
|
|
||||||
<h1 className={styles.heading}>{header.heading}</h1>
|
|
||||||
</Typography>
|
|
||||||
<Typography variant="Body/Lead text">
|
|
||||||
<p>{header.preamble}</p>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
{header.top_primary_button?.url ? (
|
|
||||||
<ButtonLink
|
|
||||||
href={header.top_primary_button.url}
|
|
||||||
size="Medium"
|
|
||||||
variant="Tertiary"
|
|
||||||
className={styles.button}
|
|
||||||
>
|
|
||||||
{header.top_primary_button.title}
|
|
||||||
</ButtonLink>
|
|
||||||
) : null}
|
|
||||||
{header.navigation_links ? (
|
|
||||||
<LinkChips chips={header.navigation_links} />
|
|
||||||
) : null}
|
|
||||||
{"dynamic_content" in header &&
|
|
||||||
header.dynamic_content !== null &&
|
|
||||||
header.dynamic_content !== undefined ? (
|
|
||||||
<HeaderDynamicContent {...header.dynamic_content} />
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{hero_video || hero_image ? (
|
|
||||||
<div className={styles.heroWrapper}>
|
|
||||||
{hero_video ? (
|
|
||||||
<HeroVideo
|
|
||||||
className={styles.heroVideo}
|
|
||||||
src={hero_video.src}
|
|
||||||
focalPoint={hero_video.focalPoint}
|
|
||||||
captions={hero_video.captions}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{!hero_video && hero_image ? (
|
|
||||||
<Hero
|
|
||||||
className={styles.heroImage}
|
|
||||||
alt={hero_image.meta.alt || hero_image.meta.caption || ""}
|
|
||||||
src={hero_image.url}
|
|
||||||
focalPoint={hero_image.focalPoint}
|
|
||||||
dimensions={hero_image.dimensions}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div className={styles.contentContainer}>
|
|
||||||
<main className={styles.mainContent}>
|
|
||||||
{pageType === "collection" && meeting_package?.show_widget && (
|
|
||||||
<MeetingPackageWidget
|
|
||||||
destination={meeting_package.location}
|
|
||||||
className={styles.meetingPackageWidget}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{blocks ? <Blocks blocks={blocks} /> : null}
|
|
||||||
</main>
|
|
||||||
|
|
||||||
{"sidebar" in content && content.sidebar?.length ? (
|
|
||||||
<Suspense fallback={<SidebarSkeleton />}>
|
|
||||||
<Sidebar blocks={content.sidebar} />
|
|
||||||
</Suspense>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<TrackingSDK pageData={tracking} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
.page {
|
|
||||||
padding-bottom: var(--Space-x9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
background-color: var(--Base-Surface-Subtle-Normal);
|
|
||||||
padding-bottom: var(--Space-x4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerContent {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x3);
|
|
||||||
max-width: var(--max-width-content);
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerIntro {
|
|
||||||
display: grid;
|
|
||||||
max-width: var(--max-width-text-block);
|
|
||||||
gap: var(--Space-x3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.heading {
|
|
||||||
color: var(--Text-Heading);
|
|
||||||
text-wrap: balance;
|
|
||||||
hyphens: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroWrapper {
|
|
||||||
padding: var(--Space-x4) var(--Space-x2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroImage,
|
|
||||||
.heroVideo {
|
|
||||||
max-width: var(--max-width-content);
|
|
||||||
margin: 0 auto;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contentContainer {
|
|
||||||
width: 100%;
|
|
||||||
padding: var(--Space-x4) var(--Space-x2) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content .contentContainer {
|
|
||||||
display: grid;
|
|
||||||
grid-template-areas:
|
|
||||||
"main"
|
|
||||||
"sidebar";
|
|
||||||
gap: var(--Space-x4);
|
|
||||||
align-items: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainContent {
|
|
||||||
display: grid;
|
|
||||||
width: 100%;
|
|
||||||
gap: var(--Space-x6);
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: var(--max-width-content);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content .mainContent {
|
|
||||||
grid-area: main;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meetingPackageWidget {
|
|
||||||
border-radius: var(--Corner-radius-lg);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.contentContainer {
|
|
||||||
padding: var(--Space-x4) 0;
|
|
||||||
max-width: var(--max-width-content);
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroContainer {
|
|
||||||
padding: var(--Space-x4) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerIntro {
|
|
||||||
gap: var(--Space-x3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Meeting booking widget changes design at 948px */
|
|
||||||
@media screen and (min-width: 948px) {
|
|
||||||
.meetingPackageWidget {
|
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
|
||||||
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1367px) {
|
|
||||||
.content .contentContainer {
|
|
||||||
grid-template-areas: "main sidebar";
|
|
||||||
grid-template-columns: var(--max-width-text-block) 1fr;
|
|
||||||
gap: var(--Space-x9);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainContent {
|
|
||||||
gap: var(--Space-x9);
|
|
||||||
padding: 0;
|
|
||||||
max-width: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import type { TrackingSDKPageData } from "@scandic-hotels/tracking/types"
|
|
||||||
import type { CollectionPage } from "@scandic-hotels/trpc/types/collectionPage"
|
|
||||||
import type { ContentPage } from "@scandic-hotels/trpc/types/contentPage"
|
|
||||||
import type { VariantProps } from "class-variance-authority"
|
|
||||||
|
|
||||||
import type { staticPageVariants } from "./variants"
|
|
||||||
|
|
||||||
export interface StaticPageProps
|
|
||||||
extends Omit<React.HTMLAttributes<HTMLDivElement>, "content">,
|
|
||||||
VariantProps<typeof staticPageVariants> {
|
|
||||||
pageType?: "collection" | "content"
|
|
||||||
content: CollectionPage["collection_page"] | ContentPage["content_page"]
|
|
||||||
tracking: TrackingSDKPageData
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { cva } from "class-variance-authority"
|
|
||||||
|
|
||||||
import styles from "./staticPage.module.css"
|
|
||||||
|
|
||||||
export const staticPageVariants = cva(styles.page, {
|
|
||||||
variants: {
|
|
||||||
pageType: {
|
|
||||||
collection: styles.collection,
|
|
||||||
content: styles.content,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultVariants: {
|
|
||||||
pageType: "content",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import type { FocalPoint } from "@scandic-hotels/common/utils/imageVault"
|
|
||||||
import type { Image } from "@scandic-hotels/trpc/types/image"
|
|
||||||
|
|
||||||
export interface HeroProps {
|
|
||||||
alt: string
|
|
||||||
src: string
|
|
||||||
focalPoint?: FocalPoint
|
|
||||||
dimensions?: Image["dimension"]
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
|
||||||
|
|
||||||
import { getMembershipCards } from "@/lib/trpc/memoizedRequests"
|
|
||||||
|
|
||||||
import { getIntl } from "@/i18n"
|
|
||||||
|
|
||||||
import styles from "./membershipcards.module.css"
|
|
||||||
|
|
||||||
export default async function MembershipCardSlot() {
|
|
||||||
const intl = await getIntl()
|
|
||||||
const membershipCards = await getMembershipCards()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className={styles.container}>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<Typography variant="Title/Subtitle/md">
|
|
||||||
<h3>
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: "myPages.myMembershipCards",
|
|
||||||
defaultMessage: "My membership cards",
|
|
||||||
})}
|
|
||||||
</h3>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
{(membershipCards || []).map((card, idx) => (
|
|
||||||
<div className={styles.card} key={idx}>
|
|
||||||
<Typography variant="Title/Subtitle/md">
|
|
||||||
<h4 className={styles.subTitle}>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "myPages.nameWithCardMembershipType",
|
|
||||||
defaultMessage: "Name: {cardMembershipType}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cardMembershipType: card.membershipType,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</h4>
|
|
||||||
</Typography>
|
|
||||||
<span>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "myPages.currentPointsWithPoints",
|
|
||||||
defaultMessage: "Current Points: {points, number}",
|
|
||||||
},
|
|
||||||
{ points: card.currentPoints }
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "myPages.memberSinceWithValue",
|
|
||||||
defaultMessage: "Member Since: {value}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: card.memberSince,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span data-hj-suppress>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "myPages.numberWithValue",
|
|
||||||
defaultMessage: "Number: {membershipNumber}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
membershipNumber: card.membershipNumber,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "myPages.expirationDateWithDate",
|
|
||||||
defaultMessage: "Expiration Date: {expirationDate}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
expirationDate: card.expirationDate?.split("T")[0],
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<Link href="#" variant="icon">
|
|
||||||
<MaterialIcon icon="add_circle" color="CurrentColor" />
|
|
||||||
<Typography
|
|
||||||
variant="Body/Paragraph/mdRegular"
|
|
||||||
className={styles.addNewCardText}
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: "myPages.addNewCard",
|
|
||||||
defaultMessage: "Add new card",
|
|
||||||
})}
|
|
||||||
</p>
|
|
||||||
</Typography>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x3);
|
|
||||||
max-width: 510px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
margin-top: var(--Space-x4);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
grid-template-rows: repeat(3, auto);
|
|
||||||
gap: var(--Space-x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.subTitle {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addNewCardText {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: var(--Scandic-Brand-Burgundy);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import type { VariantProps } from "class-variance-authority"
|
|
||||||
|
|
||||||
import type { linkVariants } from "./variants"
|
|
||||||
|
|
||||||
export interface SectionLinkProps
|
|
||||||
extends React.PropsWithChildren<React.HTMLAttributes<HTMLSpanElement>>,
|
|
||||||
VariantProps<typeof linkVariants> {
|
|
||||||
link?: { href: string; text: string }
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import type { ApiImage } from "@scandic-hotels/trpc/types/hotel"
|
|
||||||
|
|
||||||
export type PreviewImagesProps = {
|
|
||||||
images: ApiImage[]
|
|
||||||
hotelName: string
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import type { User } from "@scandic-hotels/trpc/types/user"
|
|
||||||
|
|
||||||
export interface FriendProps
|
|
||||||
extends React.PropsWithChildren<Pick<User, "membership" | "name">> {}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export type PointsColumnProps = {
|
|
||||||
title: string
|
|
||||||
subtitle?: string
|
|
||||||
value?: number | null
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import { useIntl } from "react-intl"
|
|
||||||
import { useReactToPrint } from "react-to-print"
|
|
||||||
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
|
|
||||||
|
|
||||||
import type { DownloadInvoiceProps } from "../../../../types/components/bookingConfirmation/actions/downloadInvoice"
|
|
||||||
|
|
||||||
export default function DownloadInvoice({ mainRef }: DownloadInvoiceProps) {
|
|
||||||
const intl = useIntl()
|
|
||||||
const reactToPrintFn = useReactToPrint({ contentRef: mainRef })
|
|
||||||
|
|
||||||
function downloadBooking() {
|
|
||||||
reactToPrintFn()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
intent="text"
|
|
||||||
onPress={downloadBooking}
|
|
||||||
size="small"
|
|
||||||
theme="base"
|
|
||||||
variant="icon"
|
|
||||||
wrapping
|
|
||||||
>
|
|
||||||
<MaterialIcon icon="download" color="CurrentColor" />
|
|
||||||
{intl.formatMessage({
|
|
||||||
id: "bookingConfirmation.downloadInvoice",
|
|
||||||
defaultMessage: "Download invoice",
|
|
||||||
})}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import type { MutableRefObject } from "react"
|
|
||||||
|
|
||||||
export interface DownloadInvoiceProps {
|
|
||||||
mainRef: MutableRefObject<HTMLElement | null>
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import type { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|
||||||
import type { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
|
|
||||||
import type { Room } from "@scandic-hotels/trpc/types/hotel"
|
|
||||||
import type { Package, PackageEnum } from "@scandic-hotels/trpc/types/packages"
|
|
||||||
import type {
|
|
||||||
Product,
|
|
||||||
RoomConfiguration,
|
|
||||||
RoomsAvailability,
|
|
||||||
} from "@scandic-hotels/trpc/types/roomAvailability"
|
|
||||||
|
|
||||||
import type { BookingCodeFilterEnum } from "../../stores/bookingCode-filter"
|
|
||||||
import type {
|
|
||||||
Rate,
|
|
||||||
Room as RoomBooking,
|
|
||||||
SelectRateBooking,
|
|
||||||
} from "../components/selectRate/selectRate"
|
|
||||||
|
|
||||||
export interface AvailabilityError {
|
|
||||||
details: string
|
|
||||||
error: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Actions {
|
|
||||||
appendRegularRates: (
|
|
||||||
roomConfigurations: RoomConfiguration[] | undefined
|
|
||||||
) => void
|
|
||||||
closeSection: () => void
|
|
||||||
modifyRate: () => void
|
|
||||||
removeSelectedPackage: (code: PackageEnum) => void
|
|
||||||
removeSelectedPackages: () => void
|
|
||||||
selectFilter: (filter: BookingCodeFilterEnum) => void
|
|
||||||
selectPackages: (codes: PackageEnum[]) => void
|
|
||||||
selectRate: (rate: SelectedRate, isUserLoggedIn: boolean) => void
|
|
||||||
updateRooms: (rooms: RoomConfiguration[] | undefined) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SelectedRate {
|
|
||||||
features: RoomConfiguration["features"]
|
|
||||||
product: Product
|
|
||||||
roomType: RoomConfiguration["roomType"]
|
|
||||||
roomTypeCode: RoomConfiguration["roomTypeCode"]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SelectedRoom {
|
|
||||||
actions: Actions
|
|
||||||
bookingRoom: RoomBooking
|
|
||||||
isFetchingAdditionalRate: boolean
|
|
||||||
isFetchingPackages: boolean
|
|
||||||
rooms: RoomConfiguration[]
|
|
||||||
selectedFilter: BookingCodeFilterEnum | undefined
|
|
||||||
selectedPackages: Package[]
|
|
||||||
selectedRate: SelectedRate | null
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DefaultFilterOptions {
|
|
||||||
code: RoomPackageCodeEnum
|
|
||||||
description: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RatesState {
|
|
||||||
activeRoom: number
|
|
||||||
booking: SelectRateBooking
|
|
||||||
hotelType: string | undefined
|
|
||||||
isRedemptionBooking: boolean
|
|
||||||
packageOptions: DefaultFilterOptions[]
|
|
||||||
rateSummary: Array<Rate | null>
|
|
||||||
rooms: SelectedRoom[]
|
|
||||||
roomCategories: Room[]
|
|
||||||
roomConfigurations: RoomConfiguration[][]
|
|
||||||
roomsPackages: Package[][]
|
|
||||||
roomsAvailability: (RoomsAvailability | AvailabilityError)[] | undefined
|
|
||||||
vat: number
|
|
||||||
defaultCurrency: CurrencyEnum
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InitialState
|
|
||||||
extends Pick<
|
|
||||||
RatesState,
|
|
||||||
"booking" | "hotelType" | "roomCategories" | "roomsAvailability" | "vat"
|
|
||||||
> {
|
|
||||||
initialActiveRoom?: number
|
|
||||||
pathname: string
|
|
||||||
labels: {
|
|
||||||
accessibilityRoom: string
|
|
||||||
allergyRoom: string
|
|
||||||
petRoom: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { Contact } from "../Contact.graphql"
|
|
||||||
|
|
||||||
export const ContactAside = gql`
|
|
||||||
fragment ContactAside on CurrentBlocksPageAsideContact {
|
|
||||||
contact {
|
|
||||||
contactConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...Contact
|
|
||||||
}
|
|
||||||
}
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${Contact}
|
|
||||||
`
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { Puff } from "../Puff.graphql"
|
|
||||||
|
|
||||||
export const PuffAside = gql`
|
|
||||||
fragment PuffAside on CurrentBlocksPageAsidePuff {
|
|
||||||
puff {
|
|
||||||
...Puff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${Puff}
|
|
||||||
`
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const ListItem = gql`
|
|
||||||
fragment ListItem on CurrentBlocksPageBlocksListBlockListItemsListItem {
|
|
||||||
list_item {
|
|
||||||
list_item_style
|
|
||||||
subtitle
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ListItemExternalLink = gql`
|
|
||||||
fragment ListItemExternalLink on CurrentBlocksPageBlocksListBlockListItemsListItemExternalLink {
|
|
||||||
list_item_external_link {
|
|
||||||
link {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
list_item_style
|
|
||||||
subtitle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ListBlock = gql`
|
|
||||||
fragment ListBlock on CurrentBlocksPageBlocksList {
|
|
||||||
list {
|
|
||||||
list_items {
|
|
||||||
__typename
|
|
||||||
...ListItem
|
|
||||||
...ListItemExternalLink
|
|
||||||
}
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${ListItem}
|
|
||||||
${ListItemExternalLink}
|
|
||||||
`
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { Puff } from "../Puff.graphql"
|
|
||||||
|
|
||||||
export const PuffBlock = gql`
|
|
||||||
fragment PuffBlock on CurrentBlocksPageBlocksPuffs {
|
|
||||||
puffs {
|
|
||||||
puffs {
|
|
||||||
... on CurrentBlocksPageBlocksPuffsBlockPuffsPuff {
|
|
||||||
puff {
|
|
||||||
...Puff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${Puff}
|
|
||||||
`
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "../SysAsset.graphql"
|
|
||||||
|
|
||||||
export const TextBlock = gql`
|
|
||||||
fragment TextBlock on CurrentBlocksPageBlocksText {
|
|
||||||
text {
|
|
||||||
content {
|
|
||||||
embedded_itemsConnection {
|
|
||||||
totalCount
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
json
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const CurrentBlocksPageBreadcrumbs = gql`
|
|
||||||
fragment CurrentBlocksPageBreadcrumbs on CurrentBlocksPage {
|
|
||||||
breadcrumbs {
|
|
||||||
parents {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { System } from "../System.graphql"
|
|
||||||
|
|
||||||
export const PromoCampaignPageBreadcrumb = gql`
|
|
||||||
fragment PromoCampaignPageBreadcrumb on PromoCampaignPage {
|
|
||||||
web {
|
|
||||||
breadcrumbs {
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
url
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const PromoCampaignPageBreadcrumbRef = gql`
|
|
||||||
fragment PromoCampaignPageBreadcrumbRef on PromoCampaignPage {
|
|
||||||
web {
|
|
||||||
breadcrumbs {
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
`
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const ContactExtraInfo = gql`
|
|
||||||
fragment ContactExtraInfo on ContactBlockSectionsExtraInfo {
|
|
||||||
extra_info {
|
|
||||||
text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ContactMailingAddress = gql`
|
|
||||||
fragment ContactMailingAddress on ContactBlockSectionsMailingAddress {
|
|
||||||
mailing_address {
|
|
||||||
city
|
|
||||||
country
|
|
||||||
name
|
|
||||||
street
|
|
||||||
zip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ContactPhone = gql`
|
|
||||||
fragment ContactPhone on ContactBlockSectionsPhone {
|
|
||||||
phone {
|
|
||||||
number
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ContactTitle = gql`
|
|
||||||
fragment ContactTitle on ContactBlockSectionsTitle {
|
|
||||||
title {
|
|
||||||
text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const ContactVisitingAddress = gql`
|
|
||||||
fragment ContactVisitingAddress on ContactBlockSectionsVisitingAddress {
|
|
||||||
visiting_address {
|
|
||||||
city
|
|
||||||
country
|
|
||||||
street
|
|
||||||
zip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const Contact = gql`
|
|
||||||
fragment Contact on ContactBlock {
|
|
||||||
sections {
|
|
||||||
__typename
|
|
||||||
...ContactExtraInfo
|
|
||||||
...ContactMailingAddress
|
|
||||||
...ContactPhone
|
|
||||||
...ContactTitle
|
|
||||||
...ContactVisitingAddress
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
locale
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${ContactExtraInfo}
|
|
||||||
${ContactMailingAddress}
|
|
||||||
${ContactPhone}
|
|
||||||
${ContactTitle}
|
|
||||||
${ContactVisitingAddress}
|
|
||||||
`
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "../SysAsset.graphql"
|
|
||||||
|
|
||||||
export const CurrentFooterAppDownloads = gql`
|
|
||||||
fragment CurrentFooterAppDownloads on CurrentFooter {
|
|
||||||
app_downloads {
|
|
||||||
title
|
|
||||||
app_store {
|
|
||||||
href
|
|
||||||
imageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
google_play {
|
|
||||||
href
|
|
||||||
imageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "../SysAsset.graphql"
|
|
||||||
|
|
||||||
export const Logo = gql`
|
|
||||||
fragment Logo on CurrentFooter {
|
|
||||||
logoConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const MainLinks = gql`
|
|
||||||
fragment MainLinks on Footer {
|
|
||||||
main_links {
|
|
||||||
title
|
|
||||||
open_in_new_tab
|
|
||||||
link {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
pageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
... on AccountPage {
|
|
||||||
title
|
|
||||||
url
|
|
||||||
}
|
|
||||||
... on LoyaltyPage {
|
|
||||||
title
|
|
||||||
url
|
|
||||||
}
|
|
||||||
... on ContentPage {
|
|
||||||
title
|
|
||||||
url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const Navigation = gql`
|
|
||||||
fragment Navigation on CurrentFooter {
|
|
||||||
navigation {
|
|
||||||
links {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { AccountPageRef } from "../../AccountPage/Ref.graphql"
|
|
||||||
import { ContentPageRef } from "../../ContentPage/Ref.graphql"
|
|
||||||
import { LoyaltyPageRef } from "../../LoyaltyPage/Ref.graphql"
|
|
||||||
import { System } from "../../System.graphql"
|
|
||||||
|
|
||||||
export const MainLinksRef = gql`
|
|
||||||
fragment MainLinksRef on Footer {
|
|
||||||
__typename
|
|
||||||
main_links {
|
|
||||||
pageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...LoyaltyPageRef
|
|
||||||
...ContentPageRef
|
|
||||||
...AccountPageRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
${LoyaltyPageRef}
|
|
||||||
${AccountPageRef}
|
|
||||||
${ContentPageRef}
|
|
||||||
`
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { AccountPageRef } from "../../AccountPage/Ref.graphql"
|
|
||||||
import { ContentPageRef } from "../../ContentPage/Ref.graphql"
|
|
||||||
import { LoyaltyPageRef } from "../../LoyaltyPage/Ref.graphql"
|
|
||||||
import { System } from "../../System.graphql"
|
|
||||||
|
|
||||||
export const SecondaryLinksRef = gql`
|
|
||||||
fragment SecondaryLinksRef on Footer {
|
|
||||||
__typename
|
|
||||||
secondary_links {
|
|
||||||
links {
|
|
||||||
pageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...LoyaltyPageRef
|
|
||||||
...ContentPageRef
|
|
||||||
...AccountPageRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
${LoyaltyPageRef}
|
|
||||||
${AccountPageRef}
|
|
||||||
${ContentPageRef}
|
|
||||||
`
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const SecondaryLinks = gql`
|
|
||||||
fragment SecondaryLinks on Footer {
|
|
||||||
secondary_links {
|
|
||||||
title
|
|
||||||
links {
|
|
||||||
title
|
|
||||||
open_in_new_tab
|
|
||||||
pageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
link {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const CurrentFooterSocialMedia = gql`
|
|
||||||
fragment CurrentFooterSocialMedia on CurrentFooter {
|
|
||||||
social_media {
|
|
||||||
title
|
|
||||||
facebook {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
instagram {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
twitter {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "../SysAsset.graphql"
|
|
||||||
|
|
||||||
export const TripAdvisor = gql`
|
|
||||||
fragment TripAdvisor on CurrentFooter {
|
|
||||||
trip_advisor {
|
|
||||||
logoConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { AccountPageRef } from "../../AccountPage/Ref.graphql"
|
|
||||||
import { ContentPageRef } from "../../ContentPage/Ref.graphql"
|
|
||||||
import { LoyaltyPageRef } from "../../LoyaltyPage/Ref.graphql"
|
|
||||||
|
|
||||||
export const TertiaryLinksRef = gql`
|
|
||||||
fragment TertiaryLinksRef on Footer {
|
|
||||||
__typename
|
|
||||||
tertiary_links {
|
|
||||||
pageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...LoyaltyPageRef
|
|
||||||
...ContentPageRef
|
|
||||||
...AccountPageRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${LoyaltyPageRef}
|
|
||||||
${AccountPageRef}
|
|
||||||
${ContentPageRef}
|
|
||||||
`
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const Grid = gql`
|
|
||||||
fragment Grid on Grid {
|
|
||||||
columns {
|
|
||||||
span
|
|
||||||
rows {
|
|
||||||
rowConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
... on Card {
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "./SysAsset.graphql"
|
|
||||||
|
|
||||||
export const Hero = gql`
|
|
||||||
fragment Hero on Hero {
|
|
||||||
imagesConnection {
|
|
||||||
totalCount
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { System } from "../System.graphql"
|
|
||||||
|
|
||||||
export const CurrentBlocksPageLink = gql`
|
|
||||||
fragment CurrentBlocksPageLink on CurrentBlocksPage {
|
|
||||||
title
|
|
||||||
url
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
`
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { System } from "../System.graphql"
|
|
||||||
|
|
||||||
export const CurrentBlocksPageLink = gql`
|
|
||||||
fragment CurrentBlocksPageLink on CurrentBlocksPage {
|
|
||||||
title
|
|
||||||
url
|
|
||||||
system {
|
|
||||||
...System
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
`
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "./SysAsset.graphql"
|
|
||||||
|
|
||||||
export const Preamble = gql`
|
|
||||||
fragment Preamble on CurrentBlocksPage {
|
|
||||||
preamble {
|
|
||||||
text {
|
|
||||||
json
|
|
||||||
embedded_itemsConnection(limit: 30) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
import { SysAsset } from "./SysAsset.graphql"
|
|
||||||
|
|
||||||
export const Puff = gql`
|
|
||||||
fragment Puff on Puff {
|
|
||||||
imageConnection {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
...SysAsset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
puff_style
|
|
||||||
link {
|
|
||||||
href
|
|
||||||
title
|
|
||||||
}
|
|
||||||
text {
|
|
||||||
json
|
|
||||||
}
|
|
||||||
title
|
|
||||||
}
|
|
||||||
${SysAsset}
|
|
||||||
`
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { gql } from "graphql-tag"
|
|
||||||
|
|
||||||
export const GetRewards = gql`
|
|
||||||
query GetRewards($locale: String!, $rewardIds: [String!]) {
|
|
||||||
all_reward(locale: $locale, where: { reward_id_in: $rewardIds }) {
|
|
||||||
items {
|
|
||||||
taxonomies {
|
|
||||||
term_uid
|
|
||||||
}
|
|
||||||
label
|
|
||||||
grouped_label
|
|
||||||
description
|
|
||||||
grouped_description
|
|
||||||
value
|
|
||||||
reward_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
# GraphQL to TypeScript Converter
|
|
||||||
|
|
||||||
This script converts GraphQL files (`.graphql`) to TypeScript files (`.graphql.ts`) that use the `gql` template literal from `graphql-tag`.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Converts individual fragments and queries into separate TypeScript exports
|
|
||||||
- Handles GraphQL imports (`#import`) and converts them to TypeScript imports
|
|
||||||
- Preserves fragment references and generates proper import statements
|
|
||||||
- Groups multiple imports from the same file
|
|
||||||
- Supports fragments, queries, mutations, and subscriptions
|
|
||||||
- Handles files with multiple operations
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Basic Conversion
|
|
||||||
|
|
||||||
Convert all GraphQL files in the project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn graphql:convert
|
|
||||||
```
|
|
||||||
|
|
||||||
Convert files matching a specific pattern:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn graphql:convert "packages/trpc/**/*.graphql"
|
|
||||||
```
|
|
||||||
|
|
||||||
Convert a single file:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn graphql:convert "path/to/file.graphql"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
- `--dry-run`: Preview what files would be converted without actually converting them
|
|
||||||
- `--delete-originals`: Delete original `.graphql` files after successful conversion
|
|
||||||
- `--help`, `-h`: Show help message
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
Preview conversion:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn graphql:convert --dry-run
|
|
||||||
```
|
|
||||||
|
|
||||||
Convert and delete originals:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn graphql:convert --delete-originals
|
|
||||||
```
|
|
||||||
|
|
||||||
Convert specific directory:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yarn graphql:convert "packages/trpc/lib/graphql/Fragments/**/*.graphql"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Input Format
|
|
||||||
|
|
||||||
### GraphQL Fragment
|
|
||||||
|
|
||||||
```graphql
|
|
||||||
fragment Contact on ContactBlock {
|
|
||||||
sections {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### GraphQL Query with Imports
|
|
||||||
|
|
||||||
```graphql
|
|
||||||
#import "../Fragments/System.graphql"
|
|
||||||
#import "../Fragments/Metadata.graphql"
|
|
||||||
|
|
||||||
query GetData($locale: String!) {
|
|
||||||
data(locale: $locale) {
|
|
||||||
...System
|
|
||||||
...Metadata
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output Format
|
|
||||||
|
|
||||||
### TypeScript Fragment
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { gql } from "graphql-tag";
|
|
||||||
|
|
||||||
export const Contact = gql`
|
|
||||||
fragment Contact on ContactBlock {
|
|
||||||
sections {
|
|
||||||
__typename
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
```
|
|
||||||
|
|
||||||
### TypeScript Query with Imports
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { gql } from "graphql-tag";
|
|
||||||
|
|
||||||
import { System } from "../Fragments/System.graphql";
|
|
||||||
import { Metadata } from "../Fragments/Metadata.graphql";
|
|
||||||
|
|
||||||
export const GetData = gql`
|
|
||||||
query GetData($locale: String!) {
|
|
||||||
data(locale: $locale) {
|
|
||||||
...System
|
|
||||||
...Metadata
|
|
||||||
}
|
|
||||||
}
|
|
||||||
${System}
|
|
||||||
${Metadata}
|
|
||||||
`;
|
|
||||||
```
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
1. **Parse GraphQL Files**: Reads `.graphql` files and extracts imports and operations
|
|
||||||
2. **Handle Imports**: Converts `#import` statements to TypeScript imports by:
|
|
||||||
- Reading the imported file to determine export names
|
|
||||||
- Converting paths from `.graphql` to `.graphql.ts`
|
|
||||||
- Grouping multiple imports from the same file
|
|
||||||
3. **Extract Operations**: Identifies fragments, queries, mutations, and subscriptions
|
|
||||||
4. **Generate TypeScript**: Creates TypeScript files with:
|
|
||||||
- `gql` template literals
|
|
||||||
- Proper import statements
|
|
||||||
- Named exports for each operation
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
- `glob`: For file pattern matching
|
|
||||||
- `tsx`: For TypeScript execution
|
|
||||||
- `@types/node`: For Node.js types
|
|
||||||
- `graphql-tag`: For the `gql` template literal (runtime dependency)
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- The script preserves the original file structure and naming
|
|
||||||
- Fragment references (`...FragmentName`) are preserved in the GraphQL content
|
|
||||||
- Multiple operations in a single file are split into separate exports
|
|
||||||
- Import conflicts are avoided by using the exact export names from referenced files
|
|
||||||
- Generated files maintain the same directory structure with `.graphql.ts` extension
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
#!/usr/bin/env tsx
|
|
||||||
|
|
||||||
import * as fs from "fs";
|
|
||||||
import * as path from "path";
|
|
||||||
import { glob } from "glob";
|
|
||||||
|
|
||||||
interface ImportInfo {
|
|
||||||
fragmentName: string;
|
|
||||||
importPath: string;
|
|
||||||
variableName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GraphQLFile {
|
|
||||||
content: string;
|
|
||||||
imports: ImportInfo[];
|
|
||||||
operations: Array<{ name: string; content: string }>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts individual fragments/operations from GraphQL content
|
|
||||||
*/
|
|
||||||
function extractOperations(
|
|
||||||
content: string
|
|
||||||
): Array<{ name: string; content: string }> {
|
|
||||||
const operations: Array<{ name: string; content: string }> = [];
|
|
||||||
|
|
||||||
// Split content into lines for processing
|
|
||||||
const lines = content.split("\n");
|
|
||||||
let currentOperation: { name: string; content: string[] } | null = null;
|
|
||||||
let braceCount = 0;
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
const trimmedLine = line.trim();
|
|
||||||
|
|
||||||
// Check if this line starts a new operation
|
|
||||||
const fragmentMatch = trimmedLine.match(/^fragment\s+(\w+)\s+on/);
|
|
||||||
const queryMatch = trimmedLine.match(/^query\s+(\w+)\s*[({]/);
|
|
||||||
const mutationMatch = trimmedLine.match(/^mutation\s+(\w+)\s*[({]/);
|
|
||||||
const subscriptionMatch = trimmedLine.match(
|
|
||||||
/^subscription\s+(\w+)\s*[({]/
|
|
||||||
);
|
|
||||||
|
|
||||||
if (fragmentMatch || queryMatch || mutationMatch || subscriptionMatch) {
|
|
||||||
// Finish previous operation if exists
|
|
||||||
if (currentOperation && currentOperation.content.length > 0) {
|
|
||||||
operations.push({
|
|
||||||
name: currentOperation.name,
|
|
||||||
content: currentOperation.content.join("\n").trim(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start new operation
|
|
||||||
const operationName = (fragmentMatch ||
|
|
||||||
queryMatch ||
|
|
||||||
mutationMatch ||
|
|
||||||
subscriptionMatch)![1];
|
|
||||||
currentOperation = {
|
|
||||||
name: operationName,
|
|
||||||
content: [line],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Count braces in the current line
|
|
||||||
braceCount =
|
|
||||||
(line.match(/{/g) || []).length -
|
|
||||||
(line.match(/}/g) || []).length;
|
|
||||||
} else if (currentOperation) {
|
|
||||||
// Add line to current operation
|
|
||||||
currentOperation.content.push(line);
|
|
||||||
|
|
||||||
// Update brace count
|
|
||||||
braceCount +=
|
|
||||||
(line.match(/{/g) || []).length -
|
|
||||||
(line.match(/}/g) || []).length;
|
|
||||||
|
|
||||||
// If we've closed all braces, this operation is complete
|
|
||||||
if (braceCount === 0 && trimmedLine.includes("}")) {
|
|
||||||
operations.push({
|
|
||||||
name: currentOperation.name,
|
|
||||||
content: currentOperation.content.join("\n").trim(),
|
|
||||||
});
|
|
||||||
currentOperation = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle case where file ends without closing brace
|
|
||||||
if (currentOperation && currentOperation.content.length > 0) {
|
|
||||||
operations.push({
|
|
||||||
name: currentOperation.name,
|
|
||||||
content: currentOperation.content.join("\n").trim(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return operations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates TypeScript content from parsed GraphQL
|
|
||||||
*/
|
|
||||||
function generateTypeScriptContent(parsedFile: GraphQLFile): string {
|
|
||||||
const { imports, operations } = parsedFile;
|
|
||||||
|
|
||||||
let output = 'import { gql } from "graphql-tag"\n';
|
|
||||||
|
|
||||||
// Add imports for fragments - group by import path to avoid duplicates
|
|
||||||
if (imports.length > 0) {
|
|
||||||
output += "\n";
|
|
||||||
|
|
||||||
const importsByPath = new Map<string, string[]>();
|
|
||||||
for (const imp of imports) {
|
|
||||||
if (!importsByPath.has(imp.importPath)) {
|
|
||||||
importsByPath.set(imp.importPath, []);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!importsByPath.get(imp.importPath)!.includes(imp.variableName)
|
|
||||||
) {
|
|
||||||
importsByPath.get(imp.importPath)!.push(imp.variableName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [importPath, variableNames] of importsByPath) {
|
|
||||||
output += `import { ${variableNames.join(", ")} } from "${importPath}"\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output += "\n";
|
|
||||||
|
|
||||||
// Generate exports for each operation
|
|
||||||
if (operations.length === 0) {
|
|
||||||
// If no operation names found, use a default export
|
|
||||||
const defaultName = "GraphQLDocument";
|
|
||||||
const fragmentSubstitutions =
|
|
||||||
imports.length > 0
|
|
||||||
? "\n" +
|
|
||||||
imports.map((imp) => `\${${imp.variableName}}`).join("\n")
|
|
||||||
: "";
|
|
||||||
output += `export const ${defaultName} = gql\`\n${parsedFile.content}${fragmentSubstitutions}\n\`\n`;
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < operations.length; i++) {
|
|
||||||
const operation = operations[i];
|
|
||||||
const fragmentSubstitutions =
|
|
||||||
imports.length > 0
|
|
||||||
? "\n" +
|
|
||||||
imports.map((imp) => `\${${imp.variableName}}`).join("\n")
|
|
||||||
: "";
|
|
||||||
output += `export const ${operation.name} = gql\`\n${operation.content}${fragmentSubstitutions}\n\`\n`;
|
|
||||||
|
|
||||||
if (i < operations.length - 1) {
|
|
||||||
output += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a GraphQL import path to a TypeScript import path
|
|
||||||
*/
|
|
||||||
function convertImportPath(graphqlPath: string): string {
|
|
||||||
// Remove the .graphql extension and add .graphql
|
|
||||||
const withoutExt = graphqlPath.replace(/\.graphql$/, "");
|
|
||||||
return `${withoutExt}.graphql`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the export names from a GraphQL file by analyzing the fragments it contains
|
|
||||||
*/
|
|
||||||
function getExportNamesFromGraphQLFile(filePath: string): string[] {
|
|
||||||
try {
|
|
||||||
const content = fs.readFileSync(filePath, "utf-8");
|
|
||||||
const operations = extractOperations(content);
|
|
||||||
return operations.map((op) => op.name);
|
|
||||||
} catch {
|
|
||||||
// If file doesn't exist or can't be read, try to infer from path
|
|
||||||
console.warn(
|
|
||||||
`Warning: Could not read ${filePath}, inferring export name from path`
|
|
||||||
);
|
|
||||||
return [getVariableNameFromPath(filePath)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the expected variable name from a file path
|
|
||||||
*/
|
|
||||||
function getVariableNameFromPath(filePath: string): string {
|
|
||||||
const basename = path.basename(filePath, ".graphql");
|
|
||||||
|
|
||||||
// Convert kebab-case or snake_case to PascalCase
|
|
||||||
return basename
|
|
||||||
.split(/[-_]/)
|
|
||||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
||||||
.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a GraphQL file and extracts imports and content
|
|
||||||
*/
|
|
||||||
function parseGraphQLFile(filePath: string): GraphQLFile {
|
|
||||||
const content = fs.readFileSync(filePath, "utf-8");
|
|
||||||
const lines = content.split("\n");
|
|
||||||
const imports: ImportInfo[] = [];
|
|
||||||
const contentLines: string[] = [];
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
const trimmedLine = line.trim();
|
|
||||||
|
|
||||||
if (trimmedLine.startsWith("#import")) {
|
|
||||||
// Extract import path from #import "path"
|
|
||||||
const match = trimmedLine.match(/#import\s+"([^"]+)"/);
|
|
||||||
if (match) {
|
|
||||||
const importPath = match[1];
|
|
||||||
const fullImportPath = path.resolve(
|
|
||||||
path.dirname(filePath),
|
|
||||||
importPath
|
|
||||||
);
|
|
||||||
const exportNames =
|
|
||||||
getExportNamesFromGraphQLFile(fullImportPath);
|
|
||||||
const tsImportPath = convertImportPath(importPath);
|
|
||||||
|
|
||||||
// Add all exports from the imported file
|
|
||||||
for (const exportName of exportNames) {
|
|
||||||
imports.push({
|
|
||||||
fragmentName: exportName,
|
|
||||||
importPath: tsImportPath,
|
|
||||||
variableName: exportName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (trimmedLine && !trimmedLine.startsWith("#")) {
|
|
||||||
contentLines.push(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cleanContent = contentLines.join("\n").trim();
|
|
||||||
const operations = extractOperations(cleanContent);
|
|
||||||
|
|
||||||
return {
|
|
||||||
content: cleanContent,
|
|
||||||
imports,
|
|
||||||
operations,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a single GraphQL file to TypeScript
|
|
||||||
*/
|
|
||||||
function convertFile(graphqlPath: string): void {
|
|
||||||
try {
|
|
||||||
console.log(`Converting: ${graphqlPath}`);
|
|
||||||
|
|
||||||
const parsed = parseGraphQLFile(graphqlPath);
|
|
||||||
const tsContent = generateTypeScriptContent(parsed);
|
|
||||||
const tsPath = graphqlPath.replace(/\.graphql$/, ".graphql.ts");
|
|
||||||
|
|
||||||
fs.writeFileSync(tsPath, tsContent, "utf-8");
|
|
||||||
console.log(`✓ Created: ${tsPath}`);
|
|
||||||
|
|
||||||
// Optionally remove the original .graphql file
|
|
||||||
// Uncomment the next line if you want to delete the original files
|
|
||||||
// fs.unlinkSync(graphqlPath)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error converting ${graphqlPath}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main function to convert all GraphQL files
|
|
||||||
*/
|
|
||||||
async function main() {
|
|
||||||
const args = process.argv.slice(2);
|
|
||||||
|
|
||||||
if (args.includes("--help") || args.includes("-h")) {
|
|
||||||
console.log(`
|
|
||||||
GraphQL to TypeScript Converter
|
|
||||||
|
|
||||||
Converts GraphQL files (.graphql) to TypeScript files (.graphql.ts) using gql template literals.
|
|
||||||
|
|
||||||
Usage: tsx convert-graphql-to-ts.ts [options] [pattern]
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--help, -h Show this help message
|
|
||||||
--dry-run Show what files would be converted without converting them
|
|
||||||
--delete-originals Delete original .graphql files after conversion
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
tsx convert-graphql-to-ts.ts # Convert all .graphql files
|
|
||||||
tsx convert-graphql-to-ts.ts "packages/trpc/**/*.graphql" # Convert specific pattern
|
|
||||||
tsx convert-graphql-to-ts.ts --dry-run # Preview conversion
|
|
||||||
tsx convert-graphql-to-ts.ts --delete-originals # Convert and delete originals
|
|
||||||
|
|
||||||
Features:
|
|
||||||
• Converts fragments, queries, mutations, and subscriptions
|
|
||||||
• Handles GraphQL imports (#import) and converts to TypeScript imports
|
|
||||||
• Preserves fragment references and generates proper import statements
|
|
||||||
• Groups multiple imports from the same file
|
|
||||||
• Splits multiple operations into separate exports
|
|
||||||
`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dryRun = args.includes("--dry-run");
|
|
||||||
const deleteOriginals = args.includes("--delete-originals");
|
|
||||||
|
|
||||||
// Get the pattern from args or use default
|
|
||||||
const pattern = args.find((arg) => !arg.startsWith("--")) || "**/*.graphql";
|
|
||||||
|
|
||||||
console.log(`🔍 Searching for GraphQL files with pattern: ${pattern}`);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const files = await glob(pattern, {
|
|
||||||
ignore: ["**/*.graphql.ts", "**/node_modules/**"],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (files.length === 0) {
|
|
||||||
console.log("❌ No GraphQL files found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`📁 Found ${files.length} GraphQL files`);
|
|
||||||
|
|
||||||
if (dryRun) {
|
|
||||||
console.log("\n📋 Files that would be converted:");
|
|
||||||
files.forEach((file, index) => {
|
|
||||||
console.log(
|
|
||||||
` ${index + 1}. ${file} → ${file.replace(/\.graphql$/, ".graphql.ts")}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
console.log("\n🔍 --dry-run mode: No files were converted.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("\n🔄 Converting files...");
|
|
||||||
let successCount = 0;
|
|
||||||
let errorCount = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
const file = files[i];
|
|
||||||
try {
|
|
||||||
console.log(
|
|
||||||
`📝 [${i + 1}/${files.length}] Converting: ${file}`
|
|
||||||
);
|
|
||||||
convertFile(file);
|
|
||||||
successCount++;
|
|
||||||
|
|
||||||
if (deleteOriginals) {
|
|
||||||
fs.unlinkSync(file);
|
|
||||||
console.log(`🗑️ Deleted: ${file}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`❌ Error converting ${file}:`, error);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`\n✅ Conversion complete!`);
|
|
||||||
console.log(` 📈 Successfully converted: ${successCount} files`);
|
|
||||||
if (errorCount > 0) {
|
|
||||||
console.log(` ❌ Errors: ${errorCount} files`);
|
|
||||||
}
|
|
||||||
if (deleteOriginals && successCount > 0) {
|
|
||||||
console.log(` 🗑️ Deleted: ${successCount} original files`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("❌ Error:", error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the script
|
|
||||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
||||||
main().catch(console.error);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user