Start on UserContent

This commit is contained in:
austinkelsay 2024-03-26 18:14:32 -05:00
parent aca8c6ee82
commit 6952a12d1a
13 changed files with 308 additions and 94 deletions

View File

@ -1,11 +1,10 @@
import React, { useState, useEffect, use } from 'react';
import { Carousel } from 'primereact/carousel';
import { useRouter } from 'next/router';
import Image from 'next/image';
import { useImageProxy } from '@/hooks/useImageProxy';
import { parseEvent } from '@/utils/nostr';
import { formatTimestampToHowLongAgo } from '@/utils/time';
import { useNostr } from '@/hooks/useNostr';
import CourseTemplate from '@/components/content/carousels/templates/CourseTemplate';
const responsiveOptions = [
{
@ -80,43 +79,10 @@ export default function CoursesCarousel() {
setProcessedCourses(processCourses);
}, [courses]);
const courseTemplate = (course) => {
const { width, height } = calculateImageDimensions();
return (
<div style={{width: width < 768 ? "auto" : width}} onClick={() => router.push(`/details/${course.id}`)} className="flex flex-col items-center mx-auto px-4 cursor-pointer mt-8 rounded-md shadow-lg">
<div style={{maxWidth: width, minWidth: width}} className="max-tab:h-auto max-mob:h-auto">
<Image
alt="resource thumbnail"
src={returnImageProxy(course.image)}
quality={100}
width={width}
height={height}
className="w-full h-full object-cover object-center rounded-md"
/>
<div className='flex flex-col justify-start'>
<h4 className="mb-1 font-bold text-2xl font-blinker">{course.title}</h4>
<p style={{
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: 3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'prewrap',
font: '400 1rem/1.5 Blinker, sans-serif'
}}>
{course.summary}
</p>
<p className="text-sm mt-1 text-gray-400">Published: {formatTimestampToHowLongAgo(course.published_at)}</p>
</div>
</div>
</div>
);
};
return (
<>
<h2 className="ml-[6%] mt-4">courses</h2>
<Carousel value={[...processedCourses, ...processedCourses]} numVisible={2} itemTemplate={courseTemplate} responsiveOptions={responsiveOptions} />
<Carousel value={[...processedCourses, ...processedCourses]} numVisible={2} itemTemplate={CourseTemplate} responsiveOptions={responsiveOptions} />
</>
);
}

View File

@ -1,11 +1,10 @@
import React, { useState, useEffect } from 'react';
import { Carousel } from 'primereact/carousel';
import { useRouter } from 'next/router';
import Image from 'next/image';
import { useNostr } from '@/hooks/useNostr';
import { useImageProxy } from '@/hooks/useImageProxy';
import { parseEvent } from '@/utils/nostr';
import { formatTimestampToHowLongAgo } from '@/utils/time';
import WorkshopTemplate from '@/components/content/carousels/templates/WorkshopTemplate';
const responsiveOptions = [
{
@ -78,43 +77,10 @@ export default function WorkshopsCarousel() {
setProcessedWorkshops(processWorkshops);
}, [workshops]);
const workshopTemplate = (workshop) => {
const { width, height } = calculateImageDimensions();
return (
<div style={{width: width < 768 ? "auto" : width}} onClick={() => router.push(`/details/${workshop.id}`)} className="flex flex-col items-center mx-auto px-4 cursor-pointer mt-8 rounded-md shadow-lg">
<div style={{maxWidth: width, minWidth: width}} className="max-tab:h-auto max-mob:h-auto">
<Image
alt="resource thumbnail"
src={returnImageProxy(workshop.image)}
quality={100}
width={width}
height={height}
className="w-full h-full object-cover object-center rounded-md"
/>
<div className='flex flex-col justify-start'>
<h4 className="mb-1 font-bold text-2xl font-blinker">{workshop.title}</h4>
<p style={{
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: 3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'prewrap',
font: '400 1rem/1.5 Blinker, sans-serif'
}}>
{workshop.summary}
</p>
<p className="text-sm mt-1 text-gray-400 font-blinker">Published: {formatTimestampToHowLongAgo(workshop.published_at)}</p>
</div>
</div>
</div>
);
};
return (
<>
<h2 className="ml-[6%] mt-4">workshops</h2>
<Carousel value={[...processedWorkshops, ...processedWorkshops]} numVisible={2} itemTemplate={workshopTemplate} responsiveOptions={responsiveOptions} />
<Carousel value={[...processedWorkshops, ...processedWorkshops]} numVisible={2} itemTemplate={WorkshopTemplate} responsiveOptions={responsiveOptions} />
</>
);
}

View File

@ -0,0 +1,43 @@
import React from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import useResponsiveImageDimensions from "@/hooks/useResponsiveImageDimensions";
import { formatTimestampToHowLongAgo } from "@/utils/time";
import { useImageProxy } from "@/hooks/useImageProxy";
const CourseTemplate = (course) => {
const router = useRouter();
const { returnImageProxy } = useImageProxy();
const { width, height } = useResponsiveImageDimensions();
return (
<div style={{width: width < 768 ? "auto" : width}} onClick={() => router.push(`/details/${course.id}`)} className="flex flex-col items-center mx-auto px-4 cursor-pointer mt-8 rounded-md shadow-lg">
<div style={{maxWidth: width, minWidth: width}} className="max-tab:h-auto max-mob:h-auto">
<Image
alt="resource thumbnail"
src={returnImageProxy(course.image)}
quality={100}
width={width}
height={height}
className="w-full h-full object-cover object-center rounded-md"
/>
<div className='flex flex-col justify-start'>
<h4 className="mb-1 font-bold text-2xl font-blinker">{course.title}</h4>
<p style={{
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: 3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'prewrap',
font: '400 1rem/1.5 Blinker, sans-serif'
}}>
{course.summary}
</p>
<p className="text-sm mt-1 text-gray-400">Published: {formatTimestampToHowLongAgo(course.published_at)}</p>
</div>
</div>
</div>
);
};
export default CourseTemplate;

View File

@ -0,0 +1,43 @@
import React from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import useResponsiveImageDimensions from "@/hooks/useResponsiveImageDimensions";
import { formatTimestampToHowLongAgo } from "@/utils/time";
import { useImageProxy } from "@/hooks/useImageProxy";
const ResourceTemplate = (resource) => {
const router = useRouter();
const { returnImageProxy } = useImageProxy();
const { width, height } = useResponsiveImageDimensions();
return (
<div style={{width: width < 768 ? "auto" : width}} onClick={() => router.push(`/details/${resource.id}`)} className="flex flex-col items-center mx-auto px-4 cursor-pointer mt-8 rounded-md shadow-lg">
<div style={{maxWidth: width, minWidth: width}} className="max-tab:h-auto max-mob:h-auto">
<Image
alt="resource thumbnail"
src={returnImageProxy(resource.image)}
quality={100}
width={width}
height={height}
className="w-full h-full object-cover object-center rounded-md"
/>
<div className='flex flex-col justify-start'>
<h4 className="mb-1 font-bold text-2xl font-blinker">{resource.title}</h4>
<p style={{
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: 3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'prewrap',
font: '400 1rem/1.5 Blinker, sans-serif'
}}>
{resource.summary}
</p>
<p className="text-sm mt-1 text-gray-400">Published: {formatTimestampToHowLongAgo(resource.published_at)}</p>
</div>
</div>
</div>
);
};
export default ResourceTemplate;

View File

@ -0,0 +1,43 @@
import React from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import useResponsiveImageDimensions from "@/hooks/useResponsiveImageDimensions";
import { formatTimestampToHowLongAgo } from "@/utils/time";
import { useImageProxy } from "@/hooks/useImageProxy";
const WorkshopTemplate = (workshop) => {
const router = useRouter();
const { returnImageProxy } = useImageProxy();
const { width, height } = useResponsiveImageDimensions();
return (
<div style={{width: width < 768 ? "auto" : width}} onClick={() => router.push(`/details/${workshop.id}`)} className="flex flex-col items-center mx-auto px-4 cursor-pointer mt-8 rounded-md shadow-lg">
<div style={{maxWidth: width, minWidth: width}} className="max-tab:h-auto max-mob:h-auto">
<Image
alt="workshop thumbnail"
src={returnImageProxy(workshop.image)}
quality={100}
width={width}
height={height}
className="w-full h-full object-cover object-center rounded-md"
/>
<div className='flex flex-col justify-start'>
<h4 className="mb-1 font-bold text-2xl font-blinker">{workshop.title}</h4>
<p style={{
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: 3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'prewrap',
font: '400 1rem/1.5 Blinker, sans-serif'
}}>
{workshop.summary}
</p>
<p className="text-sm mt-1 text-gray-400">Published: {formatTimestampToHowLongAgo(workshop.published_at)}</p>
</div>
</div>
</div>
);
};
export default WorkshopTemplate;

View File

@ -0,0 +1,24 @@
import React from "react";
import { DataView } from 'primereact/dataview';
import ContentListItem from "@/components/content/lists/ContentListItem";
const ContentList = ({content}) => {
const listTemplate = (items) => {
if (!items || items.length === 0) return null;
let list = items.map((item, index) => {
return ContentListItem(item);
});
return <div className="grid grid-nogutter">{list}</div>;
};
return (
<DataView
value={content}
listTemplate={listTemplate}
/>
)
}
export default ContentList;

View File

@ -0,0 +1,40 @@
import React from "react";
import Image from "next/image";
import { Button } from "primereact/button";
import { useImageProxy } from "@/hooks/useImageProxy";
import { useRouter } from "next/router";
const ContentListItem = (content) => {
const { returnImageProxy } = useImageProxy();
const router = useRouter();
const isDraft = Object.keys(content).includes('type');
return (
<div className="p-4 border-bottom-1 surface-border" key={content.id}>
<div className="flex flex-column md:flex-row gap-4">
<Image
alt="content thumbnail"
src={returnImageProxy(content.image)}
width={150}
height={100}
className="w-full md:w-[150px] h-[100px] object-cover object-center border-round"
/>
<div className="flex-1">
<div className="text-xl text-900 font-bold mb-2">{content.title}</div>
<div className="flex align-items-center text-600 gap-2 mb-2">
<span>{content.summary}</span>
</div>
<div className="text-right">
<Button
onClick={() => router.push(`${ isDraft ? '/draft' : '/details' }/${content.id}`)}
label="Open"
outlined
/>
</div>
</div>
</div>
</div>
);
};
export default ContentListItem;

View File

@ -17,7 +17,7 @@ const CourseForm = () => {
const [coverImage, setCoverImage] = useState('');
const [topics, setTopics] = useState(['']);
const {showToast} = useToast();
const { showToast } = useToast();
const handleSubmit = (e) => {
e.preventDefault();

View File

@ -0,0 +1,104 @@
import React, { useState, useEffect } from "react";
import axios from "axios";
import { useRouter } from "next/router";
import { Button } from "primereact/button";
import MenuTab from "@/components/menutab/MenuTab";
import { useLocalStorageWithEffect } from "@/hooks/useLocalStorage";
import { useImageProxy } from "@/hooks/useImageProxy";
import useResponsiveImageDimensions from "@/hooks/useResponsiveImageDimensions";
import ContentList from "@/components/content/lists/ContentList";
const fakeProducts = [
{
id: 'p1',
name: 'Eco-Friendly Water Bottle',
image: 'eco-friendly-water-bottle.jpg',
category: 'Kitchenware',
rating: 4,
price: 19.99,
inventoryStatus: 'INSTOCK'
},
{
id: 'p2',
name: 'Wireless Bluetooth Headphones',
image: 'wireless-bluetooth-headphones.jpg',
category: 'Electronics',
rating: 5,
price: 89.99,
inventoryStatus: 'LOWSTOCK'
},
{
id: 'p3',
name: 'Organic Cotton T-Shirt',
image: 'organic-cotton-t-shirt.jpg',
category: 'Apparel',
rating: 3,
price: 29.99,
inventoryStatus: 'OUTOFSTOCK'
},
{
id: 'p4',
name: 'Smartwatch Fitness Tracker',
image: 'smartwatch-fitness-tracker.jpg',
category: 'Wearables',
rating: 4,
price: 49.99,
inventoryStatus: 'INSTOCK'
},
{
id: 'p5',
name: 'Sustainable Bamboo Sunglasses',
image: 'sustainable-bamboo-sunglasses.jpg',
category: 'Accessories',
rating: 4,
price: 34.99,
inventoryStatus: 'INSTOCK'
}
];
const UserContent = () => {
const [activeIndex, setActiveIndex] = useState(0);
const [content, setContent] = useState([]);
const [user, setUser] = useLocalStorageWithEffect('user', {});
const { returnImageProxy } = useImageProxy();
const { width, height } = useResponsiveImageDimensions();
const router = useRouter();
const homeItems = [
{ label: 'Publised', icon: 'pi pi-verified' },
{ label: 'Drafts', icon: 'pi pi-file-edit' },
{ label: 'Resources', icon: 'pi pi-book' },
{ label: 'Workshops', icon: 'pi pi-video' },
{ label: 'Courses', icon: 'pi pi-desktop' }
];
useEffect(() => {
axios.get(`/api/drafts/all/${user.id}`)
.then(res => {
console.log(res.data);
setContent(res.data);
})
.catch(err => {
console.error(err);
});
}, [user]);
return (
<div className="w-[90vw] mx-auto max-tab:w-[100vw] max-mob:w-[100vw]">
<div className="border-y-2 border-gray-300 mt-12">
<h2 className="text-center my-4">Your Content</h2>
</div>
<div className="flex flex-row w-full justify-between px-4">
<MenuTab items={homeItems} activeIndex={activeIndex} onTabChange={setActiveIndex} />
<Button onClick={() => router.push('/create')} label="Create" severity="success" outlined className="mt-2" />
</div>
<div className="w-full mx-auto my-8">
<ContentList content={content} />
</div>
</div>
)
}
export default UserContent;

View File

@ -5,7 +5,7 @@ const { id } = req.query;
if (req.method === 'GET') {
try {
const resource = await getAllDraftsByUserId(parseInt(id));
const resource = await getAllDraftsByUserId(id);
if (resource) {
res.status(200).json(resource);
} else {

View File

@ -1,7 +1,7 @@
import Head from 'next/head'
import React from 'react';
import CoursesCarousel from '@/components/courses/CoursesCarousel'
import WorkshopsCarousel from '@/components/workshops/WorkshopsCarousel'
import CoursesCarousel from '@/components/content/carousels/CoursesCarousel'
import WorkshopsCarousel from '@/components/content/carousels/WorkshopsCarousel'
import HeroBanner from '@/components/banner/HeroBanner';
export default function Home() {

View File

@ -6,22 +6,13 @@ import { Column } from 'primereact/column';
import { useImageProxy } from "@/hooks/useImageProxy";
import { useRouter } from "next/router";
import { useLocalStorageWithEffect } from "@/hooks/useLocalStorage";
import MenuTab from "@/components/menutab/MenuTab";
import UserContent from '@/components/profile/UserContent';
import Image from "next/image";
const Profile = () => {
const [activeIndex, setActiveIndex] = useState(0);
const [user, setUser] = useLocalStorageWithEffect('user', {});
const { returnImageProxy } = useImageProxy();
const menu = useRef(null);
const router = useRouter();
const homeItems = [
{ label: 'All', icon: 'pi pi-star' },
{ label: 'Resources', icon: 'pi pi-book' },
{ label: 'Workshops', icon: 'pi pi-video' },
{ label: 'Courses', icon: 'pi pi-desktop' }
];
const purchases = [
// {
@ -106,13 +97,7 @@ const Profile = () => {
<Column field="category" header="Category"></Column>
<Column field="date" header="Date"></Column>
</DataTable>
<div className="border-y-2 border-gray-300 mt-12">
<h2 className="text-center my-4">Your Content</h2>
</div>
<div className="flex flex-row w-full justify-between px-4">
<MenuTab items={homeItems} activeIndex={activeIndex} onTabChange={setActiveIndex} />
<Button onClick={() => router.push('/create')} label="Create" severity="success" outlined className="mt-2" />
</div>
<UserContent />
</div>
)
)

View File

@ -79,4 +79,4 @@ h3 {
.p-tabmenu .p-tabmenu-nav::-webkit-scrollbar {
display: none;
}
}