[chore] moving things around in prep for graphql

This commit is contained in:
2025-11-27 00:28:53 -05:00
parent 90d6562f45
commit dc014a08ce
7 changed files with 307 additions and 236 deletions

View File

@@ -1,7 +1,7 @@
import React, { ReactElement } from "react";
import Select from "react-select";
export const Menu = (props): ReactElement => {
export const Menu = (props: any): ReactElement => {
const {
filteredActionOptions,
customStyles,
@@ -13,11 +13,11 @@ export const Menu = (props): ReactElement => {
<Select
components={{ Placeholder }}
placeholder={
<span className="inline-flex flex-row items-center gap-2 pt-1">
<div className="w-6 h-6">
<i className="icon-[solar--cursor-bold-duotone] w-6 h-6"></i>
<span className="inline-flex flex-row items-center gap-1.5 pt-1">
<div className="w-4 h-4">
<i className="icon-[solar--cursor-bold-duotone] w-4 h-4"></i>
</div>
<div>Select An Action</div>
<div className="text-sm">Select An Action</div>
</span>
}
styles={customStyles}

View File

@@ -18,7 +18,6 @@ import { VolumeInformation } from "./Tabs/VolumeInformation";
import { isEmpty, isUndefined, isNil, filter } from "lodash";
import { components } from "react-select";
import { RootState } from "threetwo-ui-typings";
import "react-sliding-pane/dist/react-sliding-pane.css";
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
@@ -37,20 +36,30 @@ import { refineQuery } from "filename-parser";
interface ComicDetailProps {
data: {
_id: string;
rawFileDetails: {};
inferredMetadata: {
issue: {};
rawFileDetails?: any;
inferredMetadata?: {
issue?: {
year?: string;
name?: string;
number?: number;
subtitle?: string;
};
};
sourcedMetadata: {
comicvine: {};
locg: {};
comicInfo: {};
comicvine?: any;
locg?: any;
comicInfo?: any;
};
acquisition?: {
directconnect?: {
downloads?: any[];
};
torrent?: any[];
};
acquisition: {};
createdAt: string;
updatedAt: string;
};
userSettings: {};
userSettings?: any;
}
/**
* Component for displaying the metadata for a comic in greater detail.
@@ -102,7 +111,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
const StyledSlidingPanel = styled(SlidingPane)`
background: #ccc;
`;
const afterOpenModal = useCallback((things) => {
const afterOpenModal = useCallback((things: any) => {
// references are now sync'd and can be accessed.
// subtitle.style.color = "#f00";
console.log("kolaveri", things);
@@ -113,9 +122,9 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
}, []);
// sliding panel init
const contentForSlidingPanel = {
const contentForSlidingPanel: Record<string, { content: (props?: any) => JSX.Element }> = {
CVMatches: {
content: (props) => (
content: (props?: any) => (
<>
<div>
<ComicVineSearchForm data={rawFileDetails} />
@@ -123,7 +132,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
<div className="border-slate-500 border rounded-lg p-2 mt-3">
<p className="">Searching for:</p>
{inferredMetadata.issue ? (
{inferredMetadata?.issue ? (
<>
<span className="">{inferredMetadata.issue.name} </span>
<span className=""> # {inferredMetadata.issue.number} </span>
@@ -148,9 +157,9 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
// Actions
const fetchComicVineMatches = async (
searchPayload,
issueSearchQuery,
seriesSearchQuery,
searchPayload: any,
issueSearchQuery: any,
seriesSearchQuery: any,
) => {
try {
const response = await axios({
@@ -170,7 +179,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
},
rawFileDetails: searchPayload,
},
transformResponse: (r) => {
transformResponse: (r: string) => {
const matches = JSON.parse(r);
return matches;
// return sortBy(matches, (match) => -match.score);
@@ -180,9 +189,9 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
if (!isNil(response.data.results) && response.data.results.length === 1) {
matches = response.data.results;
} else {
matches = response.data.map((match) => match);
matches = response.data.map((match: any) => match);
}
const scoredMatches = matches.sort((a, b) => b.score - a.score);
const scoredMatches = matches.sort((a: any, b: any) => b.score - a.score);
setComicVineMatches(scoredMatches);
} catch (err) {
console.log(err);
@@ -191,13 +200,13 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
// Action event handlers
const openDrawerWithCVMatches = () => {
let seriesSearchQuery: IComicVineSearchQuery = {} as IComicVineSearchQuery;
let issueSearchQuery: IComicVineSearchQuery = {} as IComicVineSearchQuery;
let seriesSearchQuery: any = {};
let issueSearchQuery: any = {};
if (!isUndefined(rawFileDetails)) {
issueSearchQuery = refineQuery(rawFileDetails.name);
issueSearchQuery = refineQuery((rawFileDetails as any).name);
} else if (!isEmpty(comicvine)) {
issueSearchQuery = refineQuery(comicvine.name);
issueSearchQuery = refineQuery((comicvine as any).name);
}
fetchComicVineMatches(rawFileDetails, issueSearchQuery, seriesSearchQuery);
setSlidingPanelContentId("CVMatches");
@@ -211,30 +220,30 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
// Actions menu options and handler
const CVMatchLabel = (
<span className="inline-flex flex-row items-center gap-2">
<div className="w-6 h-6">
<i className="icon-[solar--magic-stick-3-bold-duotone] w-6 h-6"></i>
<span className="inline-flex flex-row items-center gap-1.5">
<div className="w-4 h-4">
<i className="icon-[solar--magic-stick-3-bold-duotone] w-4 h-4"></i>
</div>
<div>Match on ComicVine</div>
<div className="text-sm">Match on ComicVine</div>
</span>
);
const editLabel = (
<span className="inline-flex flex-row items-center gap-2">
<div className="w-6 h-6">
<i className="icon-[solar--pen-2-bold-duotone] w-6 h-6"></i>
<span className="inline-flex flex-row items-center gap-1.5">
<div className="w-4 h-4">
<i className="icon-[solar--pen-2-bold-duotone] w-4 h-4"></i>
</div>
<div>Edit Metadata</div>
<div className="text-sm">Edit Metadata</div>
</span>
);
const deleteLabel = (
<span className="inline-flex flex-row items-center gap-2">
<div className="w-6 h-6">
<i className="icon-[solar--trash-bin-trash-bold-duotone] w-6 h-6"></i>
<span className="inline-flex flex-row items-center gap-1.5">
<div className="w-4 h-4">
<i className="icon-[solar--trash-bin-trash-bold-duotone] w-4 h-4"></i>
</div>
<div>Delete Comic</div>
<div className="text-sm">Delete Comic</div>
</span>
);
const Placeholder = (props) => {
const Placeholder = (props: any) => {
return <components.Placeholder {...props} />;
};
const actionOptions = [
@@ -249,7 +258,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
}
return item;
});
const handleActionSelection = (action) => {
const handleActionSelection = (action: any) => {
switch (action.value) {
case "match-on-comic-vine":
openDrawerWithCVMatches();
@@ -263,23 +272,23 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
}
};
const customStyles = {
menu: (base) => ({
menu: (base: any) => ({
...base,
backgroundColor: "rgb(156, 163, 175)",
}),
placeholder: (base) => ({
placeholder: (base: any) => ({
...base,
color: "black",
}),
option: (base, { data, isDisabled, isFocused, isSelected }) => ({
option: (base: any, { data, isDisabled, isFocused, isSelected }: any) => ({
...base,
backgroundColor: isFocused ? "gray" : "rgb(156, 163, 175)",
}),
singleValue: (base) => ({
singleValue: (base: any) => ({
...base,
paddingTop: "0.4rem",
}),
control: (base) => ({
control: (base: any) => ({
...base,
backgroundColor: "rgb(156, 163, 175)",
color: "black",
@@ -289,7 +298,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
// check for the availability of CV metadata
const isComicBookMetadataAvailable =
!isUndefined(comicvine) && !isUndefined(comicvine.volumeInformation);
!isUndefined(comicvine) && !isUndefined((comicvine as any)?.volumeInformation);
// check for the availability of rawFileDetails
const areRawFileDetailsAvailable =
@@ -354,7 +363,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
query={airDCPPQuery}
comicObjectId={_id}
comicObject={data.data}
userSettings={userSettings}
settings={userSettings}
key={4}
/>
),
@@ -376,8 +385,8 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
name: "Downloads",
icon: (
<>
{acquisition?.directconnect?.downloads?.length +
acquisition?.torrent.length}
{(acquisition?.directconnect?.downloads?.length || 0) +
(acquisition?.torrent?.length || 0)}
</>
),
content:
@@ -414,11 +423,12 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
imageUrl={url}
orientation={"cover-only"}
hasDetails={false}
cardContainerStyle={{ maxWidth: "290px", width: "100%" }}
/>
{/* raw file details */}
{!isUndefined(rawFileDetails) &&
!isEmpty(rawFileDetails.cover) && (
!isEmpty((rawFileDetails as any)?.cover) && (
<div className="grid">
<RawFileDetails
data={{
@@ -468,7 +478,7 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
<TabControls
filteredTabs={filteredTabs}
downloadCount={acquisition?.directconnect?.downloads?.length}
downloadCount={acquisition?.directconnect?.downloads?.length || 0}
/>
<StyledSlidingPanel

View File

@@ -30,94 +30,125 @@ interface RawFileDetailsProps {
children?: any;
}
export const RawFileDetails = (props: RawFileDetailsProps): ReactElement => {
export const RawFileDetails = (props: RawFileDetailsProps): ReactElement | null => {
const { rawFileDetails, inferredMetadata, created_at, updated_at } =
props.data;
props.data || {};
if (!rawFileDetails) return null;
return (
<>
<div className="max-w-2xl ml-5">
<div className="px-4 sm:px-6">
{/* Title */}
<div className="px-4 sm:px-6 mb-6">
<p className="text-gray-500 dark:text-gray-400">
<span className="text-xl">{rawFileDetails.name}</span>
<span className="text-xl font-semibold">{rawFileDetails?.name}</span>
</p>
</div>
<div className="px-4 py-5 sm:px-6">
<dl className="grid grid-cols-1 gap-x-4 gap-y-4 sm:grid-cols-2">
<div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">
Raw File Details
</dt>
<dd className="mt-1 text-sm text-gray-900 dark:text-gray-400">
{rawFileDetails.containedIn +
"/" +
rawFileDetails.name +
rawFileDetails.extension}
</dd>
</div>
<div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">
Inferred Issue Metadata
</dt>
<dd className="mt-1 text-sm text-gray-900 dark:text-gray-400">
Series Name: {inferredMetadata.issue.name}
{!isEmpty(inferredMetadata.issue.number) ? (
<span className="tag is-primary is-light">
{inferredMetadata.issue.number}
</span>
) : null}
</dd>
</div>
<div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">
MIMEType
</dt>
<dd className="mt-1 text-sm text-gray-500 dark:text-slate-900">
{/* File extension */}
<span className="inline-flex items-center bg-slate-50 text-slate-800 text-xs font-medium px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
<span className="pt-1">
{/* File Binary Details Section */}
<div className="mb-8 px-4 pb-8 border-b border-gray-200 dark:border-gray-700">
<div className="mb-4">
<h3 className="text-sm font-medium text-gray-600 dark:text-gray-300 uppercase tracking-wide flex items-center gap-1">
<i className="icon-[solar--document-bold-duotone] w-5 h-5"></i>
File Binary Details
</h3>
</div>
<div className="pl-6">
<dl className="space-y-4">
<div>
<dt className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide mb-1">
File Path
</dt>
<dd className="text-sm text-gray-900 dark:text-gray-300 font-mono break-all">
{rawFileDetails?.containedIn}/{rawFileDetails?.name}{rawFileDetails?.extension}
</dd>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<dt className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide mb-1">
MIME Type
</dt>
<dd className="text-sm text-gray-700 dark:text-gray-300 flex items-center gap-1">
<i className="icon-[solar--zip-file-bold-duotone] w-5 h-5"></i>
</span>
<span className="text-md text-slate-500 dark:text-slate-900">
{rawFileDetails.mimeType}
</span>
</span>
</dd>
</div>
<div className="sm:col-span-1">
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">
File Size
</dt>
<dd className="mt-1 text-sm text-gray-500 dark:text-slate-900">
{/* size */}
<span className="inline-flex items-center bg-slate-50 text-slate-800 text-xs font-medium px-2 rounded-md dark:text-slate-900 dark:bg-slate-400">
<span className="pr-1 pt-1">
{rawFileDetails?.mimeType}
</dd>
</div>
<div>
<dt className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide mb-1">
File Size
</dt>
<dd className="text-sm text-gray-700 dark:text-gray-300 flex items-center gap-1">
<i className="icon-[solar--mirror-right-bold-duotone] w-5 h-5"></i>
</span>
<span className="text-md text-slate-500 dark:text-slate-900">
{prettyBytes(rawFileDetails.fileSize)}
</span>
</span>
</dd>
</div>
<div className="sm:col-span-2">
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">
Import Details
</dt>
<dd className="mt-1 text-sm text-gray-900 dark:text-gray-400">
{format(parseISO(created_at), "dd MMMM, yyyy")},{" "}
{format(parseISO(created_at), "h aaaa")}
</dd>
</div>
<div className="sm:col-span-2">
<dt className="text-sm font-medium text-gray-500 dark:text-gray-400">
Actions
</dt>
<dd className="mt-1 text-sm text-gray-900">{props.children}</dd>
</div>
</dl>
{rawFileDetails?.fileSize ? prettyBytes(rawFileDetails.fileSize) : 'N/A'}
</dd>
</div>
</div>
</dl>
</div>
</div>
{/* Import Details Section */}
<div className="mb-8 px-4">
<div className="mb-4">
<h3 className="text-sm font-medium text-gray-600 dark:text-gray-300 uppercase tracking-wide flex items-center gap-1">
<i className="icon-[solar--import-bold-duotone] w-5 h-5"></i>
Import Details
</h3>
</div>
<div className="pl-6">
<dl className="space-y-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<dt className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide mb-1">
Imported On
</dt>
<dd className="text-sm text-gray-700 dark:text-gray-300">
{created_at ? format(parseISO(created_at), "dd MMMM, yyyy 'at' h:mm aaaa") : 'N/A'}
</dd>
</div>
<div>
<dt className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide mb-1">
Last Updated
</dt>
<dd className="text-sm text-gray-700 dark:text-gray-300">
{updated_at ? format(parseISO(updated_at), "dd MMMM, yyyy 'at' h:mm aaaa") : 'N/A'}
</dd>
</div>
</div>
{inferredMetadata?.issue && (
<div>
<dt className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide mb-1">
Inferred Metadata
</dt>
<dd className="text-sm text-gray-700 dark:text-gray-300">
<span className="font-medium">{inferredMetadata.issue.name}</span>
{!isEmpty(inferredMetadata.issue.number) && (
<span className="ml-2 text-xs text-gray-500 dark:text-gray-400">
#{inferredMetadata.issue.number}
</span>
)}
</dd>
</div>
)}
</dl>
</div>
</div>
{/* Actions Section */}
{props.children && (
<div className="px-4">
<div className="mb-3">
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wide">
Actions
</h4>
</div>
<div>{props.children}</div>
</div>
)}
</div>
</>
);

View File

@@ -14,12 +14,16 @@ import { useStore } from "../../../store";
import { useShallow } from "zustand/react/shallow";
import { escapePoundSymbol } from "../../../shared/utils/formatting.utils";
export const ArchiveOperations = (props): ReactElement => {
interface ArchiveOperationsProps {
data: any;
}
export const ArchiveOperations = (props: ArchiveOperationsProps): ReactElement => {
const { data } = props;
const { socketIOInstance } = useStore(
const { getSocket } = useStore(
useShallow((state) => ({
socketIOInstance: state.socketIOInstance,
getSocket: state.getSocket,
})),
);
const queryClient = useQueryClient();
@@ -27,21 +31,32 @@ export const ArchiveOperations = (props): ReactElement => {
const [visible, setVisible] = useState(false);
const [slidingPanelContentId, setSlidingPanelContentId] = useState("");
// current image
const [currentImage, setCurrentImage] = useState([]);
const [uncompressedArchive, setUncompressedArchive] = useState([]);
const [imageAnalysisResult, setImageAnalysisResult] = useState({});
const [currentImage, setCurrentImage] = useState<string>("");
const [uncompressedArchive, setUncompressedArchive] = useState<string[]>([]);
const [imageAnalysisResult, setImageAnalysisResult] = useState<any>({});
const [shouldRefetchComicBookData, setShouldRefetchComicBookData] =
useState(false);
const constructImagePaths = (data): Array<string> => {
const constructImagePaths = (data: string[]): Array<string> => {
return data?.map((path: string) =>
escapePoundSymbol(encodeURI(`${LIBRARY_SERVICE_HOST}/${path}`)),
);
};
// Listen to the uncompression complete event and orchestrate the final payload
socketIOInstance.on("LS_UNCOMPRESSION_JOB_COMPLETE", (data) => {
setUncompressedArchive(constructImagePaths(data?.uncompressedArchive));
});
useEffect(() => {
const socket = getSocket("/");
const handleUncompressionComplete = (data: any) => {
setUncompressedArchive(constructImagePaths(data?.uncompressedArchive));
};
socket.on("LS_UNCOMPRESSION_JOB_COMPLETE", handleUncompressionComplete);
// Cleanup listener on unmount
return () => {
socket.off("LS_UNCOMPRESSION_JOB_COMPLETE", handleUncompressionComplete);
};
}, [getSocket]);
useEffect(() => {
let isMounted = true;
@@ -58,7 +73,7 @@ export const ArchiveOperations = (props): ReactElement => {
},
transformResponse: async (responseData) => {
const parsedData = JSON.parse(responseData);
const paths = parsedData.map((pathObject) => {
const paths = parsedData.map((pathObject: any) => {
return `${pathObject.containedIn}/${pathObject.name}${pathObject.extension}`;
});
const uncompressedArchive = constructImagePaths(paths);
@@ -131,7 +146,7 @@ export const ArchiveOperations = (props): ReactElement => {
}
// sliding panel init
const contentForSlidingPanel = {
const contentForSlidingPanel: Record<string, { content: () => JSX.Element }> = {
imageAnalysis: {
content: () => {
return (
@@ -143,7 +158,7 @@ export const ArchiveOperations = (props): ReactElement => {
</pre>
) : null}
<pre className="font-hasklig mt-3 text-sm">
{JSON.stringify(imageAnalysisResult.analyzedData, null, 2)}
{JSON.stringify(imageAnalysisResult?.analyzedData, null, 2)}
</pre>
</div>
);
@@ -152,7 +167,7 @@ export const ArchiveOperations = (props): ReactElement => {
};
// sliding panel handlers
const openImageAnalysisPanel = useCallback((imageFilePath) => {
const openImageAnalysisPanel = useCallback((imageFilePath: string) => {
setSlidingPanelContentId("imageAnalysis");
analyzeImage(imageFilePath);
setCurrentImage(imageFilePath);

View File

@@ -1,4 +1,4 @@
import React, { ReactElement, useState } from "react";
import React, { ReactElement, useState, useEffect } from "react";
import { map } from "lodash";
import Card from "../shared/Carda";
import Header from "../shared/Header";
@@ -34,24 +34,35 @@ export const PullList = (): ReactElement => {
format(date, "yyyy/M/dd"),
);
// Responsive slides per view
const [slidesPerView, setSlidesPerView] = useState(1);
// keen slider
const [sliderRef, instanceRef] = useKeenSlider(
{
loop: true,
slides: {
origin: "auto",
number: 15,
perView: 5,
spacing: 15,
},
slideChanged() {
console.log("slide changed");
},
const [sliderRef, instanceRef] = useKeenSlider({
loop: true,
mode: "free-snap",
slides: {
perView: slidesPerView,
spacing: 15,
},
[
// add plugins here
],
);
slideChanged() {
console.log("slide changed");
},
});
// Update slider when slidesPerView changes
useEffect(() => {
if (instanceRef.current) {
instanceRef.current.update({
slides: {
perView: slidesPerView,
spacing: 15,
},
});
}
}, [slidesPerView, instanceRef]);
const {
data: pullList,
@@ -80,79 +91,81 @@ export const PullList = (): ReactElement => {
return (
<>
<div className="content">
<Header
headerContent="Discover"
subHeaderContent={
<span className="text-md">
Pull List aggregated for the week from{" "}
<span className="underline">
<a href="https://leagueofcomicgeeks.com">
League Of Comic Geeks
</a>
<i className="icon-[solar--arrow-right-up-outline] w-4 h-4" />
<div className="mx-auto">
<Header
headerContent="Discover"
subHeaderContent={
<span className="text-md">
Pull List aggregated for the week from{" "}
<span className="underline">
<a href="https://leagueofcomicgeeks.com">
League Of Comic Geeks
</a>
<i className="icon-[solar--arrow-right-up-outline] w-4 h-4" />
</span>
</span>
</span>
}
iconClassNames="fa-solid fa-binoculars mr-2"
link="/pull-list/all/"
/>
<div className="flex flex-row gap-5 mb-3">
{/* select week */}
<div className="flex flex-row gap-4 my-3">
<Form
onSubmit={() => {}}
render={({ handleSubmit }) => (
<form>
<div className="flex flex-col gap-2">
{/* week selection for pull list */}
<DatePickerDialog
inputValue={inputValue}
setter={setInputValue}
/>
{inputValue && (
<div className="text-sm">
Showing pull list for{" "}
<span className="inline-flex mb-2 items-center bg-slate-50 text-slate-800 text-xs font-medium px-2.5 py-1 rounded-md dark:text-slate-900 dark:bg-slate-400">
{inputValue}
</span>
</div>
)}
</div>
</form>
)}
/>
}
iconClassNames="fa-solid fa-binoculars mr-2"
link="/pull-list/all/"
/>
<div className="flex flex-row gap-5 mb-3">
{/* select week */}
<div className="flex flex-row gap-4 my-3">
<Form
onSubmit={() => {}}
render={({ handleSubmit }) => (
<form>
<div className="flex flex-col gap-2">
{/* week selection for pull list */}
<DatePickerDialog
inputValue={inputValue}
setter={setInputValue}
/>
{inputValue && (
<div className="text-sm">
Showing pull list for{" "}
<span className="inline-flex mb-2 items-center bg-slate-50 text-slate-800 text-xs font-medium px-2.5 py-1 rounded-md dark:text-slate-900 dark:bg-slate-400">
{inputValue}
</span>
</div>
)}
</div>
</form>
)}
/>
</div>
</div>
</div>
</div>
{isSuccess && !isLoading && (
<div ref={sliderRef} className="keen-slider flex flex-row">
<div ref={sliderRef} className="keen-slider">
{map(pullList?.data.result, (issue, idx) => {
return (
<div key={idx} className="keen-slider__slide">
<Card
orientation={"vertical-2"}
imageUrl={issue.coverImageUrl}
hasDetails
title={ellipsize(issue.issueName, 25)}
>
<div className="px-1">
<span className="inline-flex mb-2 items-center bg-slate-50 text-slate-800 text-xs font-medium px-2.5 py-1 rounded-md dark:text-slate-900 dark:bg-slate-400">
{issue.publicationDate}
</span>
<div className="flex flex-row justify-end">
<button
className="flex space-x-1 mb-2 sm:mt-0 sm:flex-row sm:items-center rounded-lg border border-green-400 dark:border-green-200 bg-green-200 px-2 py-1 text-gray-500 hover:bg-transparent hover:text-green-600 focus:outline-none focus:ring active:text-indigo-500"
onClick={() => addToLibrary("locg", issue)}
>
<i className="icon-[solar--add-square-bold-duotone] w-5 h-5 mr-2"></i>{" "}
Want
</button>
</div>
return (
<div key={idx} className="keen-slider__slide">
<Card
orientation={"vertical-2"}
imageUrl={issue.coverImageUrl}
hasDetails
title={ellipsize(issue.issueName, 25)}
>
<div className="px-1">
<span className="inline-flex mb-2 items-center bg-slate-50 text-slate-800 text-xs font-medium px-2.5 py-1 rounded-md dark:text-slate-900 dark:bg-slate-400">
{issue.publicationDate}
</span>
<div className="flex flex-row justify-end">
<button
className="flex space-x-1 mb-2 sm:mt-0 sm:flex-row sm:items-center rounded-lg border border-green-400 dark:border-green-200 bg-green-200 px-2 py-1 text-gray-500 hover:bg-transparent hover:text-green-600 focus:outline-none focus:ring active:text-indigo-500"
onClick={() => addToLibrary("locg", issue)}
>
<i className="icon-[solar--add-square-bold-duotone] w-5 h-5 mr-2"></i>{" "}
Want
</button>
</div>
</Card>
</div>
);
</div>
</Card>
</div>
);
})}
</div>
)}

View File

@@ -21,12 +21,13 @@ export const RecentlyImported = (
console.log(comics);
return (
<div>
<Header
headerContent="Recently Imported"
subHeaderContent="Recent Library activity such as imports, tagging, etc."
iconClassNames="fa-solid fa-binoculars mr-2"
/>
<div className="grid grid-cols-5 gap-6 mt-3">
<div className="mx-auto" style={{ maxWidth: '1400px' }}>
<Header
headerContent="Recently Imported"
subHeaderContent="Recent Library activity such as imports, tagging, etc."
iconClassNames="fa-solid fa-binoculars mr-2"
/>
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-5 xl:grid-cols-5 gap-6 mt-3">
{comics?.comics.map(
(
{
@@ -125,6 +126,7 @@ export const RecentlyImported = (
);
},
)}
</div>
</div>
</div>
);

View File

@@ -11,8 +11,8 @@ interface ICardProps {
borderColorClass?: string;
backgroundColor?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
cardContainerStyle?: PropTypes.object;
imageStyle?: PropTypes.object;
cardContainerStyle?: any;
imageStyle?: any;
}
const renderCard = (props: ICardProps): ReactElement => {
@@ -156,7 +156,7 @@ const renderCard = (props: ICardProps): ReactElement => {
return (
<div
className={`rounded-lg overflow-hidden shadow-md bg-white dark:bg-slate-800 ${
className={`rounded-2xl overflow-hidden shadow-md bg-white dark:bg-slate-800 ${
props.cardContainerStyle?.height ? "" : "aspect-[2/3]"
}`}
style={containerStyle}