add resource page view that more info redirects to
This commit is contained in:
parent
4c5466d673
commit
8de276bde5
BIN
public/app-store-badge.png
Normal file
BIN
public/app-store-badge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
BIN
public/google-play-badge.png
Normal file
BIN
public/google-play-badge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -44,7 +44,7 @@ const NavBar = () => {
|
|||||||
|
|
||||||
const Header: NextPage = () => {
|
const Header: NextPage = () => {
|
||||||
return <>
|
return <>
|
||||||
<div id="logo-row" className="flex flex-row p-4 justify-center bg-neutral-800 z-50 drop-shadow-xl">
|
<div id="logo-row" className="flex flex-row p-4 justify-center border-b border-yellow bg-neutral-800 z-50 drop-shadow-xl">
|
||||||
<div>
|
<div>
|
||||||
<Image alt="Ear listening" src="/listening-ear.svg" width={64} height={64}/>
|
<Image alt="Ear listening" src="/listening-ear.svg" width={64} height={64}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,49 +8,49 @@ import { type ChangeEvent, type Dispatch, type SetStateAction, useState } from '
|
|||||||
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
import { ChevronDownIcon } from '@heroicons/react/24/outline';
|
||||||
import { type ParsedUrlQuery, type ParsedUrlQueryInput } from 'querystring';
|
import { type ParsedUrlQuery, type ParsedUrlQueryInput } from 'querystring';
|
||||||
|
|
||||||
const ResourceEntry = ({resource}: {resource: AuditoryResource}) => {
|
export const ResourceInfo = ({resource, showMoreInfo}: {resource: AuditoryResource, showMoreInfo?: boolean}) => {
|
||||||
const ResourceInfo = ({resource}: {resource: AuditoryResource}) => {
|
const PriceIcons = ({type}: {type: PaymentType}) => {
|
||||||
const PriceIcons = ({type}: {type: PaymentType}) => {
|
switch(type) {
|
||||||
switch(type) {
|
case "FREE": {
|
||||||
case "FREE": {
|
return (
|
||||||
return (
|
<div className="pt-2 space-x-1" title="Free">
|
||||||
<div className="pt-2 space-x-1" title="Free">
|
<span className="bg-amber-100 italic rounded-lg border border-neutral-900 text-black px-2 py-[1px]">
|
||||||
<span className="bg-amber-100 italic rounded-lg border border-neutral-900 text-black px-2 py-[1px]">
|
free
|
||||||
free
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
}
|
||||||
}
|
case "SUBSCRIPTION_MONTHLY": {
|
||||||
case "SUBSCRIPTION_MONTHLY": {
|
<div className="space-x-1" title="Monthly recurring subscription">
|
||||||
<div className="space-x-1" title="Monthly recurring subscription">
|
<ArrowPathRoundedSquareIcon className="inline h-6 w-6" />
|
||||||
|
<CurrencyDollarIcon className="inline h-6 w-6 text-lime-800"/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
case "SUBSCRIPTION_WEEKLY": {
|
||||||
|
return (
|
||||||
|
<div className="space-x-1" title="Weekly recurring subscription">
|
||||||
<ArrowPathRoundedSquareIcon className="inline h-6 w-6" />
|
<ArrowPathRoundedSquareIcon className="inline h-6 w-6" />
|
||||||
<CurrencyDollarIcon className="inline h-6 w-6 text-lime-800"/>
|
<CurrencyDollarIcon className="inline h-6 w-6 text-lime-800"/>
|
||||||
</div>
|
</div>
|
||||||
}
|
)
|
||||||
case "SUBSCRIPTION_WEEKLY": {
|
|
||||||
return (
|
|
||||||
<div className="space-x-1" title="Weekly recurring subscription">
|
|
||||||
<ArrowPathRoundedSquareIcon className="inline h-6 w-6" />
|
|
||||||
<CurrencyDollarIcon className="inline h-6 w-6 text-lime-800"/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const PlatformInfo = ({platformLinks}: {platformLinks: PlatformLink[]}) => {
|
|
||||||
const platformsStr = platformLinks.map((platformLink) => {
|
const PlatformInfo = ({platformLinks}: {platformLinks: PlatformLink[]}) => {
|
||||||
return translateEnumPlatform(platformLink.platform);
|
const platformsStr = platformLinks.map((platformLink) => {
|
||||||
}).join(', ');
|
return translateEnumPlatform(platformLink.platform);
|
||||||
|
}).join(', ');
|
||||||
return (
|
|
||||||
<p>{platformsStr}</p>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4 space-x-4 flex flex-row">
|
<p>{platformsStr}</p>
|
||||||
<div className="h-full my-auto">
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4 space-x-4 flex flex-row">
|
||||||
|
<div className="h-full my-auto">
|
||||||
|
{showMoreInfo ?
|
||||||
<Link href={`resources/${resource.id}`}>
|
<Link href={`resources/${resource.id}`}>
|
||||||
<div className="w-20 sm:w-28 flex space-y-2 flex-col justify-center">
|
<div className="w-20 sm:w-28 flex space-y-2 flex-col justify-center">
|
||||||
<Image className="bg-white w-full rounded-xl drop-shadow-lg border border-neutral-400" src={`/resource_logos/${resource.icon}`} alt={`${resource.name} logo`} width={512} height={512}/>
|
<Image className="bg-white w-full rounded-xl drop-shadow-lg border border-neutral-400" src={`/resource_logos/${resource.icon}`} alt={`${resource.name} logo`} width={512} height={512}/>
|
||||||
@ -58,21 +58,27 @@ const ResourceEntry = ({resource}: {resource: AuditoryResource}) => {
|
|||||||
className="block bg-neutral-900 hover:bg-neutral-500 border border-neutral-900 text-center py-[1px] text-white rounded-lg">
|
className="block bg-neutral-900 hover:bg-neutral-500 border border-neutral-900 text-center py-[1px] text-white rounded-lg">
|
||||||
more info
|
more info
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className="grid place-items-center">
|
|
||||||
<div className="">
|
|
||||||
<h2 className="text-xs italic text-gray-600">{resource.manufacturer}</h2>
|
|
||||||
<h1 className="font-bold text-xl">{resource.name}</h1>
|
|
||||||
<PlatformInfo platformLinks={resource.platform_links}/>
|
|
||||||
<PriceIcons type={resource?.payment_options[0] ?? 'FREE'} />
|
|
||||||
</div>
|
</div>
|
||||||
|
</Link>
|
||||||
|
:
|
||||||
|
<div className="w-20 sm:w-28 flex space-y-2 flex-col justify-center">
|
||||||
|
<Image className="bg-white w-full rounded-xl drop-shadow-lg border border-neutral-400" src={`/resource_logos/${resource.icon}`} alt={`${resource.name} logo`} width={512} height={512}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="grid place-items-center">
|
||||||
|
<div className="">
|
||||||
|
<h2 className="text-xs italic text-gray-600">{resource.manufacturer}</h2>
|
||||||
|
<h1 className="font-bold text-xl">{resource.name}</h1>
|
||||||
|
<PlatformInfo platformLinks={resource.platform_links}/>
|
||||||
|
<PriceIcons type={resource?.payment_options[0] ?? 'FREE'} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
</div>
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResourceEntry = ({resource}: {resource: AuditoryResource}) => {
|
||||||
const ResourceDescription = ({description}: {description: string}) => {
|
const ResourceDescription = ({description}: {description: string}) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col p-2">
|
<div className="flex flex-col p-2">
|
||||||
@ -136,7 +142,7 @@ const ResourceEntry = ({resource}: {resource: AuditoryResource}) => {
|
|||||||
return (
|
return (
|
||||||
<tr className="divide-x-[1px] divide-slate-300">
|
<tr className="divide-x-[1px] divide-slate-300">
|
||||||
<td className="max-w-xs">
|
<td className="max-w-xs">
|
||||||
<ResourceInfo resource={resource} />
|
<ResourceInfo showMoreInfo resource={resource} />
|
||||||
</td>
|
</td>
|
||||||
<td className="w-1/4 align-top">
|
<td className="w-1/4 align-top">
|
||||||
<ResourceSkills skills={resource.skills} skillLevels={resource.skill_levels} />
|
<ResourceSkills skills={resource.skills} skillLevels={resource.skill_levels} />
|
||||||
|
@ -12,7 +12,6 @@ const Home: NextPage = () => {
|
|||||||
</Head>
|
</Head>
|
||||||
<main>
|
<main>
|
||||||
<div className="my-6">
|
<div className="my-6">
|
||||||
<p>Nothing yet</p>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
import { type InferGetStaticPropsType, type GetStaticPropsContext } from "next";
|
import { type InferGetStaticPropsType, type GetStaticPropsContext } from "next";
|
||||||
|
import { GlobeAltIcon } from '@heroicons/react/24/solid';
|
||||||
import { createProxySSGHelpers } from '@trpc/react-query/ssg';
|
import { createProxySSGHelpers } from '@trpc/react-query/ssg';
|
||||||
import { appRouter } from "~/server/api/root";
|
import { appRouter } from "~/server/api/root";
|
||||||
import { prisma } from "~/server/db";
|
import { prisma } from "~/server/db";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
|
import { ResourceInfo } from "~/components/ResourceTable";
|
||||||
|
import { type PlatformLink } from "@prisma/client";
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export const getStaticPaths = async () => {
|
export const getStaticPaths = async () => {
|
||||||
//const amountPerPage = 10;
|
|
||||||
const resources = (await prisma.auditoryResource.findMany({
|
const resources = (await prisma.auditoryResource.findMany({
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
//const pages = Math.ceil(objectCount / amountPerPage);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths: resources.map((resource) => ({
|
paths: resources.map((resource) => ({
|
||||||
@ -46,13 +49,84 @@ export async function getStaticProps(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PlatformLinkButton = ({platformLink}: {platformLink: PlatformLink}) => {
|
||||||
|
switch (platformLink.platform) {
|
||||||
|
case "APP_ANDROID": {
|
||||||
|
return (
|
||||||
|
<Link href={platformLink.link}>
|
||||||
|
<a target="_blank" rel="noopener noreferrer">
|
||||||
|
<Image className="w-full" src={`/google-play-badge.png`} alt={`Download on the Apple AppStore`} width={512} height={216}/>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case "APP_IOS": {
|
||||||
|
return (
|
||||||
|
<Link href={platformLink.link}>
|
||||||
|
<Image className="w-full" src={`/app-store-badge.png`} alt={`Download on the Apple AppStore`} width={512} height={216}/>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case "PDF": {
|
||||||
|
return (
|
||||||
|
<Link href={platformLink.link}>
|
||||||
|
<div className="bg-amber-300 border-2 px-2 h-12 align-middle border-neutral-900 rounded-lg flex flex-row space-x-2">
|
||||||
|
<GlobeAltIcon className="w-6" />
|
||||||
|
<span className="font-bold text-sm my-auto">
|
||||||
|
Website
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case "WEBSITE": {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DownloadButtons = ({platformLinks}: {platformLinks: PlatformLink[]}) => {
|
||||||
|
const buttons = platformLinks.map((paltformLink, index) => {
|
||||||
|
return (
|
||||||
|
<PlatformLinkButton key={index} platformLink={paltformLink} />
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-48 mx-auto">
|
||||||
|
{buttons}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const ResourceViewPage = (props: InferGetStaticPropsType<typeof getStaticProps>) => {
|
const ResourceViewPage = (props: InferGetStaticPropsType<typeof getStaticProps>) => {
|
||||||
const { id } = props;
|
const { id } = props;
|
||||||
const resourceQuery = api.auditoryResource.byId.useQuery({ id });
|
const resourceQuery = api.auditoryResource.byId.useQuery({ id });
|
||||||
|
|
||||||
|
if (!resourceQuery.data) {
|
||||||
|
return <>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div>
|
<div className="flex py-4 flex-col flex-col-reverse sm:flex-row divide-x max-w-2xl mx-auto">
|
||||||
{resourceQuery.data?.name ?? 'loading..'}
|
<div className="text-lg flex flex-col justify-end font-bold my-5 mr-4">
|
||||||
|
<div className="mx-4">
|
||||||
|
<h1 className="border-b mb-2 border-neutral-400">Links</h1>
|
||||||
|
<DownloadButtons platformLinks={resourceQuery.data.platform_links} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex pb-5 flex-col justify-left">
|
||||||
|
<ResourceInfo resource={resourceQuery.data} />
|
||||||
|
<div className="mx-4 text-left border border-neutral-400 rounded-xl p-4 bg-neutral-200 shadow">
|
||||||
|
<p>
|
||||||
|
{resourceQuery.data.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="ml-4 mt-4 mr-auto border-2 border-neutral-900 rounded-lg bg-neutral-600">
|
||||||
|
<span className="text-neutral-200 text-sm px-2 py-2">Ages {resourceQuery.data.ages.min}{resourceQuery.data.ages.max >= 100 ? "+" : `-${resourceQuery.data.ages.max}`}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
};
|
};
|
||||||
|
@ -4,26 +4,6 @@ import ResourceTable from "~/components/ResourceTable";
|
|||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import { parseQueryData } from "~/utils/parseSearchForm";
|
import { parseQueryData } from "~/utils/parseSearchForm";
|
||||||
|
|
||||||
/*
|
|
||||||
export async function getStaticProps() {
|
|
||||||
const ssg = createProxySSGHelpers({
|
|
||||||
router: appRouter,
|
|
||||||
ctx: {
|
|
||||||
prisma,
|
|
||||||
session: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await ssg.auditoryResource.getAll.prefetch();
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
trpcState: ssg.dehydrate(),
|
|
||||||
},
|
|
||||||
revalidate: 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Resources = () => {
|
const Resources = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { SkillLevel, Skill, Platform } from "@prisma/client";
|
import { SkillLevel, Skill, Platform, AuditoryResource } from "@prisma/client";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -15,7 +15,7 @@ export const auditoryResourceRouter = createTRPCRouter({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ...resource };
|
return { ...resource } as AuditoryResource;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
getAll: publicProcedure.query(({ ctx }) => {
|
getAll: publicProcedure.query(({ ctx }) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user