Skip to content

Commit

Permalink
Merge pull request #58 from danskernesdigitalebibliotek/DDFBRA-201-go…
Browse files Browse the repository at this point in the history
…-anonym-og-indlogget-bruger-kan-prove-lydbog

Ddfbra 201 go anonym og indlogget bruger kan prove lydbog
  • Loading branch information
ThomasGross authored Nov 27, 2024
2 parents 7db9ba9 + 8e91f79 commit 352334d
Show file tree
Hide file tree
Showing 13 changed files with 418 additions and 44 deletions.
2 changes: 1 addition & 1 deletion __tests__/url.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, test } from "vitest"

import goConfig from "@/lib/config/config"
import goConfig from "@/lib/config/goConfig"

import { resolveUrl } from "../lib/helpers/helper.routes"

Expand Down
23 changes: 22 additions & 1 deletion components/pages/workPageLayout/WorkPageLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
"use client"

import { useQuery } from "@tanstack/react-query"
import React from "react"
import React, { useState } from "react"

import { Button } from "@/components/shared/button/Button"
import Player from "@/components/shared/publizonPlayer/PublizonPlayer"
import ResponsiveDialog from "@/components/shared/responsiveDialog/ResponsiveDialog"
import SmartLink from "@/components/shared/smartLink/SmartLink"
import { useGetMaterialQuery } from "@/lib/graphql/generated/fbi/graphql"
import { resolveUrl } from "@/lib/helpers/helper.routes"

function WorkPageLayout({ wid }: { wid: string }) {
const [isPlayerOpen, setIsPlayerOpen] = useState(false)

const { data } = useQuery({
queryKey: useGetMaterialQuery.getKey({ wid }),
queryFn: useGetMaterialQuery.fetcher({ wid }),
})

// TODO: Handle potential error states
const manifestations = data?.work?.manifestations.all

const identifier = manifestations?.[0].identifiers?.[0].value || ""

const url = resolveUrl({
Expand All @@ -32,6 +37,22 @@ function WorkPageLayout({ wid }: { wid: string }) {
</SmartLink>
</Button>
)}

{identifier && (
<Button ariaLabel="Prøv lydbog" onClick={() => setIsPlayerOpen(!isPlayerOpen)}>
Prøv lydbog
</Button>
)}

<ResponsiveDialog
open={isPlayerOpen}
onOpenChange={() => {
setIsPlayerOpen(!isPlayerOpen)
}}
title="Prøv lydbog"
description="For at låne lydbogen skal du være oprettet som bruger på GO.">
<Player type="demo" identifier={identifier} />
</ResponsiveDialog>
</div>
)
}
Expand Down
110 changes: 110 additions & 0 deletions components/shared/dialog/dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"use client"

import * as DialogPrimitive from "@radix-ui/react-dialog"
import { Cross2Icon } from "@radix-ui/react-icons"
import * as React from "react"

import { cn } from "@/lib/shadcn/utils"

const Dialog = DialogPrimitive.Root

const DialogTrigger = DialogPrimitive.Trigger

const DialogPortal = DialogPrimitive.Portal

const DialogClose = DialogPrimitive.Close

const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
`z-50 fixed inset-0 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out
data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0`,
className
)}
{...props}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName

const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
`z-50 fixed left-[50%] top-[50%] m-auto grid w-[calc(100%-var(--grid-edge)*2)] max-w-[600px]
translate-x-[-50%] translate-y-[-50%] gap-grid-edge rounded-md bg-background p-grid-edge shadow-lg
duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out
data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95
data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2
data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2
data-[state=open]:slide-in-from-top-[48%] lg:gap-6 lg:p-6`,
className
)}
{...props}>
{children}
<DialogPrimitive.Close
className="absolute right-grid-edge top-grid-edge rounded-sm opacity-70 ring-offset-background
transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring
focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent
data-[state=open]:text-muted-foreground lg:right-6 lg:top-6">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName

const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col space-y-1.5 text-center", className)} {...props} />
)
DialogHeader.displayName = "DialogHeader"

const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("flex flex-col-reverse lg:flex-row lg:justify-end lg:space-x-2", className)}
{...props}
/>
)
DialogFooter.displayName = "DialogFooter"

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title ref={ref} className={cn("text-typo-heading-5", className)} {...props} />
))
DialogTitle.displayName = DialogPrimitive.Title.displayName

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-typo-caption text-muted-foreground", className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName

export {
Dialog,
DialogPortal,
DialogOverlay,
DialogTrigger,
DialogClose,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
}
96 changes: 96 additions & 0 deletions components/shared/drawer/drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"use client"

import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"

import { cn } from "@/lib/shadcn/utils"

const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
)
Drawer.displayName = "Drawer"

const DrawerTrigger = DrawerPrimitive.Trigger

const DrawerPortal = DrawerPrimitive.Portal

const DrawerClose = DrawerPrimitive.Close

const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("z-50 fixed inset-0 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName

const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
`z-50 fixed inset-x-0 bottom-0 mt-24 flex h-auto flex-col rounded-t-md bg-background px-grid-edge
pb-grid-edge`,
className
)}
{...props}>
<div className="mx-auto mt-4 h-[6px] w-[100px] rounded-full bg-background-overlay" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"

const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("grid gap-1.5 p-4 text-center", className)} {...props} />
)
DrawerHeader.displayName = "DrawerHeader"

const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />
)
DrawerFooter.displayName = "DrawerFooter"

const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title ref={ref} className={cn("text-typo-heading-5", className)} {...props} />
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName

const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-typo-caption text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName

export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}
52 changes: 52 additions & 0 deletions components/shared/publizonPlayer/PublizonPlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client"

import React, { useEffect } from "react"

import { appendAsset, removeAsset } from "@/lib/helpers/helper.scripts"

import { assets } from "./helper"

// Define mutually exclusive types for identifier and orderId
type ReaderType =
| {
type: "demo"
identifier: string
orderId?: never
}
| {
type: "rent"
orderId: string
identifier?: never
}

const Player = ({ type, orderId, identifier }: ReaderType) => {
useEffect(() => {
assets.forEach(appendAsset)

return () => {
assets.forEach(removeAsset)
}
}, [])

if (type === "rent") {
return (
<iframe
style={{ height: "300px" }}
src={`https://play.pubhub.dk/index141.html?o=${orderId}`}
className="player h-full w-full"
/>
)
}

if (type === "demo") {
return (
<iframe
style={{ height: "300px" }}
src={`https://play.pubhub.dk/index141.html?i=${identifier}`}
className="player h-full w-full rounded-base"
/>
)
}
}

export default Player
8 changes: 8 additions & 0 deletions components/shared/publizonPlayer/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { TAssetType } from "@/lib/helpers/helper.scripts"

export const assets: TAssetType[] = [
{
src: "https://play.pubhub.dk/1.3.0/js/player-kernel.min.js",
type: "script",
},
]
6 changes: 4 additions & 2 deletions components/shared/publizonReader/PublizonReader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import React, { useEffect } from "react"

import { appendAsset, readerAssets, removeAsset } from "./helper"
import { appendAsset, removeAsset } from "@/lib/helpers/helper.scripts"

import { readerAssets } from "./helper"

// Define mutually exclusive types for identifier and orderId
type ReaderType =
Expand Down Expand Up @@ -37,7 +39,7 @@ const Reader = ({ type, onBackCallback, identifier, orderId }: ReaderType) => {
delete window.onReaderBackCallback
readerAssets.forEach(removeAsset)
}
}, [])
}, [onBackCallback])

if (type === "rent") {
return (
Expand Down
35 changes: 1 addition & 34 deletions components/shared/publizonReader/helper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
type TAssetType = {
src: string
type: "script" | "link"
}
import { TAssetType } from "@/lib/helpers/helper.scripts"

export const readerAssets: TAssetType[] = [
{
Expand All @@ -21,33 +18,3 @@ export const readerAssets: TAssetType[] = [
type: "link",
},
]

export const appendAsset = ({ src, type }: TAssetType) => {
if (type === "script") {
const scriptElement = document.createElement("script")
scriptElement.src = src
scriptElement.defer = true
scriptElement.async = false
scriptElement.type = "module"
document.head.appendChild(scriptElement)
}

if (type === "link") {
const linkElement = document.createElement("link")
linkElement.href = src
linkElement.rel = "stylesheet"
document.head.appendChild(linkElement)
}
}

export const removeAsset = ({ src, type }: TAssetType) => {
if (type === "script") {
const scriptElement = document.querySelector(`script[src="${src}"]`)
scriptElement?.remove()
}

if (type === "link") {
const linkElement = document.querySelector(`link[href="${src}"]`)
linkElement?.remove()
}
}
Loading

0 comments on commit 352334d

Please sign in to comment.