11"use client" ;
22
3+ import React from "react" ;
34import { type IPaper } from "@/interface" ;
45import Image from "next/image" ;
6+ import { X } from "lucide-react" ;
57import { Eye , Download , Check } from "lucide-react" ;
68import {
79 extractBracketContent ,
@@ -13,16 +15,18 @@ import {
1315 downloadFile ,
1416} from "@/lib/utils/download" ;
1517import { Capsule } from "@/components/ui/capsule" ;
16- import Link from "next/link" ;
1718import { cn } from "@/lib/utils" ;
1819
1920interface CardProps {
2021 paper : IPaper ;
2122 onSelect : ( paper : IPaper , isSelected : boolean ) => void ;
2223 isSelected : boolean ;
24+ isShow ?: boolean ;
2325}
2426
25- const Card = ( { paper, onSelect, isSelected } : CardProps ) => {
27+ const Card = ( { paper, onSelect, isSelected, isShow= true } : CardProps ) => {
28+ const [ previewOpen , setPreviewOpen ] = React . useState ( false ) ;
29+ const [ iframeLoading , setIframeLoading ] = React . useState ( true ) ;
2630 const handleDownload = async ( paper : IPaper ) => {
2731 await downloadFile ( getSecureUrl ( paper . file_url ) , generateFileName ( paper ) ) ;
2832 } ;
@@ -34,76 +38,124 @@ const Card = ({ paper, onSelect, isSelected }: CardProps) => {
3438 const paperLink = `/paper/${ paper . _id } ` ;
3539
3640 return (
37- < div
38- className = { cn (
39- "overflow-hidden rounded-sm border-2 border-[#734DFF] bg-[#FFFFFF] font-play transition-all duration-150 hover:bg-[#EFEAFF] dark:border-[#36266D] dark:bg-[#171720] hover:dark:bg-[#262635]" ,
40- isSelected && "bg-white" ,
41- ) }
42- >
43- < Link href = { paperLink } target = "_blank" rel = "noopener noreferrer" >
44- < Image
45- src = { paper . thumbnail_url }
46- alt = { paper . subject }
47- width = { 320 }
48- height = { 180 }
49- className = "w-full object-cover p-4 pb-3 md:h-[250px]"
50- />
41+ < >
42+ < div
43+ onClick = { ( e ) => {
44+ const target = e . target as HTMLElement ;
5145
52- < div className = "justify-center" >
53- < div className = "flex flex-row items-center justify-between px-4 pb-2" >
54- < div className = "text-md font-play font-medium" >
55- { extractBracketContent ( paper . subject ) }
56- </ div >
57- < div className = "flex gap-2" >
58- < Link href = { paperLink } target = "_blank" rel = "noopener noreferrer" >
59- < Eye size = { 22 } />
60- </ Link >
61- < Download
62- size = { 20 }
63- onClick = { ( e ) => {
64- e . preventDefault ( ) ;
65- e . stopPropagation ( ) ;
66- void handleDownload ( paper ) ;
67- } }
68- className = "cursor-pointer"
69- />
46+ if ( target . closest ( "button, input, svg" ) ) return ;
47+
48+ window . open ( paperLink , "_blank" ) ;
49+ } }
50+ className = { cn (
51+ "cursor-pointer overflow-hidden rounded-sm border-2 border-[#734DFF] bg-[#FFFFFF] font-play transition-all duration-150 hover:bg-[#EFEAFF] dark:border-[#36266D] dark:bg-[#171720] hover:dark:bg-[#262635]" ,
52+ isSelected && "ring-2 ring-[#7480FF] bg-[#EFEAFF]"
53+ ) }
54+ >
55+ < Image
56+ src = { paper . thumbnail_url }
57+ alt = { paper . subject }
58+ width = { 320 }
59+ height = { 180 }
60+ className = "w-full object-cover p-4 pb-3 md:h-[250px]"
61+ />
62+ < div className = "justify-center" >
63+ < div className = "flex flex-row items-center justify-between px-4 pb-2" >
64+ < div className = "text-md font-play font-medium" >
65+ { extractBracketContent ( paper . subject ) }
66+ </ div >
7067 </ div >
71- </ div >
7268
73- < div className = "h-[1px] w-full bg-[#734DFF] dark:bg-[#36266D]" />
69+ < div className = "h-[1px] w-full bg-[#734DFF] dark:bg-[#36266D]" />
7470
75- < div className = "space-y-2 p-4" >
76- < div className = "font-play text-lg font-semibold" >
77- { extractWithoutBracketContent ( paper . subject ) }
78- </ div >
79- < div className = "flex flex-wrap gap-2" >
80- < Capsule > { paper . exam } </ Capsule >
81- < Capsule > { paper . slot } </ Capsule >
82- < Capsule > { paper . year } </ Capsule >
83- < Capsule > { paper . semester } </ Capsule >
71+ < div className = "space-y-2 p-4" >
72+ < div className = "font-play text-lg font-semibold" >
73+ { extractWithoutBracketContent ( paper . subject ) }
74+ </ div >
75+ < div className = "flex flex-wrap gap-2" >
76+ < Capsule > { paper . exam } </ Capsule >
77+ < Capsule > { paper . slot } </ Capsule >
78+ < Capsule > { paper . year } </ Capsule >
79+ < Capsule > { paper . semester } </ Capsule >
80+ </ div >
8481 </ div >
8582 </ div >
86- </ div >
87- </ Link >
8883
89- < div className = "flex items-center justify-between gap-2 px-4 pb-4 font-play" >
90- < div className = "flex items-center gap-2" >
91- < input
92- checked = { isSelected }
93- onChange = { handleCheckboxChange }
94- className = "h-5 w-5 accent-[#7480FF]"
95- type = "checkbox"
84+ < div className = "flex justify-end gap-2 px-4 pb-2" >
85+ < Eye
86+ className = "cursor-pointer transition-all duration-200 ease-out hover:scale-110"
87+ onClick = { ( e ) => {
88+ e . stopPropagation ( ) ;
89+ setIframeLoading ( true ) ;
90+ setPreviewOpen ( true ) ;
91+ } }
92+ />
93+
94+ < Download
95+ size = { 20 }
96+ onClick = { ( e ) => {
97+ e . stopPropagation ( ) ;
98+ void handleDownload ( paper ) ;
99+ } }
100+ className = "cursor-pointer"
96101 />
97- < p > Select</ p >
98102 </ div >
99- { paper . answer_key_included && (
100- < div className = "flex items-center gap-2 font-normal text-[#7480FF]" >
101- < Check color = "#7480FF" />
102- Answer Key
103- </ div >
104- ) }
103+
104+ < div className = "flex items-center justify-between gap-2 px-4 pb-4 font-play" >
105+ { isShow && < div className = "flex items-center gap-2" >
106+ < input
107+ checked = { isSelected }
108+ onChange = { ( e ) => {
109+ e . stopPropagation ( ) ;
110+ handleCheckboxChange ( ) ;
111+ } }
112+ onClick = { ( e ) => e . stopPropagation ( ) }
113+ className = "h-5 w-5 accent-[#7480FF]"
114+ type = "checkbox"
115+ />
116+ < p > Select</ p >
117+ </ div > }
118+
119+ { paper . answer_key_included && (
120+ < div className = "flex items-center gap-2 font-normal text-[#7480FF]" >
121+ < Check color = "#7480FF" />
122+ Answer Key
123+ </ div >
124+ ) }
125+ </ div >
105126 </ div >
127+
128+ { previewOpen && (
129+ < div
130+ className = "fixed inset-0 z-50 flex items-center justify-center bg-black/80"
131+ onClick = { ( ) => setPreviewOpen ( false ) }
132+ >
133+ < div
134+ className = "relative w-[95%] max-w-5xl h-[90vh] rounded-lg bg-white p-2 dark:bg-[#171720]"
135+ onClick = { ( e ) => e . stopPropagation ( ) }
136+ >
137+ < div
138+ className = { `absolute inset-0 z-50 flex items-center justify-center bg-[#070114] transition-opacity duration-300 ${
139+ iframeLoading ? "opacity-100" : "opacity-0 pointer-events-none"
140+ } `}
141+ >
142+ < div className = "w-7 h-7 rounded-full border-2 border-white/20 border-t-white animate-spin" />
106143 </ div >
144+ < button
145+ className = "absolute top-3 left-6 z-50 p-2 rounded-full bg-black/60 text-white hover:bg-black transition"
146+ onClick = { ( ) => setPreviewOpen ( false ) }
147+ >
148+ < X size = { 18 } />
149+ </ button >
150+ < iframe
151+ src = { `${ getSecureUrl ( paper . file_url ) } #toolbar=0` }
152+ className = "w-full h-full rounded-md"
153+ onLoad = { ( ) => setIframeLoading ( false ) }
154+ />
155+ </ div >
156+ </ div >
157+ ) }
158+ </ >
107159 ) ;
108160} ;
109161
0 commit comments