-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
31 changed files
with
1,052 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
Warnings: | ||
- Added the required column `updatedAt` to the `Dream` table without a default value. This is not possible if the table is not empty. | ||
*/ | ||
-- AlterTable | ||
ALTER TABLE "Dream" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/app/(site)/(internal)/dashboard/components/dreams/CurrentDreamsContainer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import {FC, useMemo} from "react"; | ||
import {useDreamsData} from "@/app/(site)/(internal)/dashboard/components/dreams/DreamsProvider"; | ||
import DreamCard from "@/app/(site)/(internal)/dashboard/components/dreams/DreamCard"; | ||
import LogDreamCard from "@/app/(site)/(internal)/dashboard/components/dreams/LogDreamCard"; | ||
import useTodayTimeRange from "@/app/(site)/hooks/useTodayTimeRange"; | ||
|
||
const CurrentDreamsContainer: FC = () => { | ||
const [startOfToday, endOfToday] = useTodayTimeRange() | ||
const {dreams} = useDreamsData() | ||
const dreamCards = useMemo(() => dreams.data | ||
.filter(dream => { | ||
const creationDate = new Date(dream.createdAt.toString()); | ||
return creationDate.getTime() >= startOfToday.getTime() && creationDate.getTime() <= endOfToday.getTime() | ||
}) | ||
.map(dream => ( | ||
<DreamCard key={dream.id} dream={dream}/> | ||
)), [dreams.data, endOfToday, startOfToday]) | ||
|
||
return ( | ||
<div className="w-3/4"> | ||
<h2 className="text-4xl phone:text-2xl font-semibold mb-8 phone:mb-4 tablet:text-center">Today - {startOfToday.toLocaleDateString("en-US", { | ||
dateStyle: "medium" | ||
})} | ||
</h2> | ||
<div className="bg-primary/20 rounded-3xl py-6 px-4 phone:p-3 w-[36rem] tablet:w-full tablet:self-center flex flex-col gap-y-6"> | ||
<LogDreamCard/> | ||
{dreamCards} | ||
</div> | ||
</div> | ||
|
||
) | ||
} | ||
|
||
export default CurrentDreamsContainer |
36 changes: 36 additions & 0 deletions
36
src/app/(site)/(internal)/dashboard/components/dreams/DreamCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import {FC, Fragment} from "react"; | ||
import {Dream} from "@prisma/client"; | ||
import {CardBody, CardHeader} from "@nextui-org/card"; | ||
import Card from "@/app/(site)/components/Card"; | ||
|
||
type Props = { | ||
dream: Dream | ||
} | ||
|
||
const DreamCard: FC<Props> = ({dream}) => { | ||
return ( | ||
<Fragment> | ||
<Card classNames={{ | ||
header: "bg-secondary", | ||
body: "bg-secondary", | ||
footer: "bg-secondary", | ||
}}> | ||
<CardHeader className="flex justify-between"> | ||
<h2>{dream.title}</h2> | ||
<p> | ||
{new Date(dream.createdAt.toString()).toLocaleTimeString("en-US", { | ||
timeStyle: 'short' | ||
})} | ||
</p> | ||
</CardHeader> | ||
<CardBody> | ||
<p> | ||
{dream.description.substring(0, Math.min(dream.description.length, 100))} | ||
</p> | ||
</CardBody> | ||
</Card> | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default DreamCard |
37 changes: 37 additions & 0 deletions
37
src/app/(site)/(internal)/dashboard/components/dreams/DreamsProvider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
"use client" | ||
|
||
import {createContext, FC, PropsWithChildren, useContext} from "react"; | ||
import useDreams, {DreamsState} from "@/app/(site)/(internal)/dashboard/components/dreams/hooks/useDreams"; | ||
import useDreamCharacters, { | ||
DreamCharactersState | ||
} from "@/app/(site)/(internal)/dashboard/components/dreams/hooks/useDreamCharacters"; | ||
import useDreamTags, {DreamTagsState} from "@/app/(site)/(internal)/dashboard/components/dreams/hooks/useDreamTags"; | ||
|
||
type DreamsContextProps = { | ||
dreams: DreamsState, | ||
characters: DreamCharactersState, | ||
tags: DreamTagsState, | ||
} | ||
|
||
const DreamsContext = createContext<DreamsContextProps | undefined>(undefined) | ||
|
||
const DreamsProvider: FC<PropsWithChildren> = ({children}) => { | ||
const dreams = useDreams() | ||
const characters = useDreamCharacters() | ||
const tags = useDreamTags() | ||
|
||
return ( | ||
<DreamsContext.Provider value={{dreams, characters, tags}}> | ||
{children} | ||
</DreamsContext.Provider> | ||
) | ||
} | ||
|
||
export default DreamsProvider | ||
|
||
export const useDreamsData = () => { | ||
const dreams = useContext(DreamsContext) | ||
if (!dreams) | ||
throw new Error("useDreams can only be used in a DreamProvider!") | ||
return dreams; | ||
} |
36 changes: 36 additions & 0 deletions
36
src/app/(site)/(internal)/dashboard/components/dreams/LogDreamCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"use client" | ||
|
||
import {FC, Fragment, useState} from "react"; | ||
import {CardBody} from "@nextui-org/card"; | ||
import CloudIcon from "@/app/(site)/components/icons/CloudIcon"; | ||
import Card from "@/app/(site)/components/Card"; | ||
import LogDreamModal from "@/app/(site)/(internal)/dashboard/components/dreams/forms/log/LogDreamModal"; | ||
|
||
const LogDreamCard: FC = () => { | ||
const [modalOpen, setModalOpen] = useState(false) | ||
|
||
return ( | ||
<Fragment> | ||
<LogDreamModal | ||
isOpen={modalOpen} | ||
onClose={() => setModalOpen(false)} | ||
/> | ||
<Card | ||
onPress={() => setModalOpen(true)} | ||
isPressable | ||
classNames={{ | ||
body: "bg-primary py-8" | ||
}} | ||
> | ||
<CardBody> | ||
<div className="flex gap-4"> | ||
<CloudIcon width={36}/> | ||
<h3 className="font-semibold text-2xl phone:text-medium self-center">Log A New Dream</h3> | ||
</div> | ||
</CardBody> | ||
</Card> | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default LogDreamCard |
96 changes: 96 additions & 0 deletions
96
src/app/(site)/(internal)/dashboard/components/dreams/forms/characters/AddCharacterForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
"use client" | ||
|
||
import {FC} from "react"; | ||
import {SubmitHandler, useForm} from "react-hook-form"; | ||
import {PostDreamCharacterDto} from "@/app/api/me/dreams/dreams.dto"; | ||
import axios from "axios"; | ||
import useSWRMutation from "swr/mutation"; | ||
import {useDreamsData} from "@/app/(site)/(internal)/dashboard/components/dreams/DreamsProvider"; | ||
import {DreamCharacter} from "@prisma/client"; | ||
import {handleAxiosError} from "@/utils/client-utils"; | ||
import {useSession} from "next-auth/react"; | ||
import toast from "react-hot-toast"; | ||
import Input from "@/app/(site)/components/Input"; | ||
import {Button} from "@nextui-org/button"; | ||
|
||
type FormProps = PostDreamCharacterDto | ||
|
||
type CreateTagsArgs = { | ||
arg: { | ||
dto: PostDreamCharacterDto | ||
} | ||
} | ||
|
||
const CreateCharacter = () => { | ||
const mutator = (url: string, {arg}: CreateTagsArgs) => axios.post<DreamCharacter | null>(url, arg.dto) | ||
return useSWRMutation('/api/me/dreams/characters', mutator) | ||
} | ||
|
||
type Props = { | ||
onSuccess?: (tag: DreamCharacter) => void | ||
} | ||
|
||
const AddCharacterForm: FC<Props> = ({onSuccess}) => { | ||
const {data: session} = useSession() | ||
const {register, handleSubmit} = useForm<FormProps>() | ||
const {trigger: createCharacter, isMutating: isCreating} = CreateCharacter() | ||
const {characters} = useDreamsData() | ||
|
||
const handleCreation = async (dto: PostDreamCharacterDto) => ( | ||
createCharacter({dto}) | ||
.then(res => { | ||
const character = res.data!! | ||
if (onSuccess) | ||
onSuccess(character) | ||
return character | ||
}) | ||
.catch(handleAxiosError) | ||
) | ||
|
||
const onSubmit: SubmitHandler<FormProps> = async (data) => { | ||
if (!session?.user) | ||
return; | ||
|
||
await toast.promise(characters.optimisticData | ||
.addOptimisticData(() => handleCreation(data), { | ||
id: '', | ||
...data, | ||
createdAt: new Date(), | ||
updatedAt: new Date(), | ||
userId: session.user.id | ||
}), | ||
{ | ||
loading: "Adding new character...", | ||
success: "Successfully added that character!", | ||
error: "Could not add that character!" | ||
} | ||
) | ||
|
||
} | ||
|
||
return ( | ||
<form onSubmit={handleSubmit(onSubmit)}> | ||
<div className="space-y-6"> | ||
<Input | ||
isRequired | ||
id="name" | ||
label="Character Name" | ||
register={register} | ||
labelPlacement="outside" | ||
placeholder="Enter the name of the character..." | ||
isDisabled={isCreating} | ||
maxLength={256} | ||
/> | ||
<Button | ||
isLoading={isCreating} | ||
isDisabled={isCreating} | ||
type="submit" | ||
color="primary" | ||
variant="shadow" | ||
>Create Character</Button> | ||
</div> | ||
</form> | ||
) | ||
} | ||
|
||
export default AddCharacterForm |
26 changes: 26 additions & 0 deletions
26
src/app/(site)/(internal)/dashboard/components/dreams/forms/characters/AddCharacterModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
"use client" | ||
|
||
import {FC} from "react"; | ||
import Modal from "@/app/(site)/components/Modal"; | ||
import AddTagForm from "@/app/(site)/(internal)/dashboard/components/dreams/forms/tags/AddTagForm"; | ||
import AddCharacterForm from "@/app/(site)/(internal)/dashboard/components/dreams/forms/characters/AddCharacterForm"; | ||
|
||
type Props = { | ||
isOpen: boolean, | ||
onClose: () => void | ||
} | ||
|
||
const AddCharacterModal: FC<Props> = ({isOpen, onClose}) => { | ||
return ( | ||
<Modal | ||
size="xl" | ||
isOpen={isOpen} | ||
onClose={onClose} | ||
title="Add New Character" | ||
> | ||
<AddCharacterForm onSuccess={onClose} /> | ||
</Modal> | ||
) | ||
} | ||
|
||
export default AddCharacterModal |
79 changes: 79 additions & 0 deletions
79
src/app/(site)/(internal)/dashboard/components/dreams/forms/log/DreamCharacterSelect.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
"use client" | ||
|
||
import {FC, Fragment, useState} from "react"; | ||
import Button from "@/app/(site)/components/Button"; | ||
import Select from "@/app/(site)/components/Select"; | ||
import {Chip} from "@nextui-org/chip"; | ||
import {SelectItem} from "@nextui-org/react"; | ||
import {DreamCharactersState} from "@/app/(site)/(internal)/dashboard/components/dreams/hooks/useDreamCharacters"; | ||
import {UseFormRegister} from "react-hook-form"; | ||
import AddCharacterModal from "@/app/(site)/(internal)/dashboard/components/dreams/forms/characters/AddCharacterModal"; | ||
|
||
type Props = { | ||
register?: UseFormRegister<any>, | ||
characters: DreamCharactersState | ||
} | ||
|
||
const DreamCharacterSelect: FC<Props> = ({characters, register}) => { | ||
const [modalOpen, setModalOpen] = useState(false) | ||
|
||
return ( | ||
<Fragment> | ||
<AddCharacterModal | ||
isOpen={modalOpen} | ||
onClose={() => setModalOpen(false)} | ||
/> | ||
<div className="flex gap-4 mb-2"> | ||
<label className="text-lg phone:text-medium text-[#EAE0FF] self-center">Dream Characters</label> | ||
<Button | ||
color="cta" | ||
size="sm" | ||
onPress={() => setModalOpen(true)} | ||
> | ||
Add New Character | ||
</Button> | ||
</div> | ||
<Select | ||
aria-label="Dream Characters" | ||
register={register} | ||
id="characters" | ||
items={characters.data} | ||
placeholder="Who was in your dream?" | ||
selectionMode={"multiple"} | ||
renderValue={(items) => { | ||
return ( | ||
<div className="flex gap-2"> | ||
{items.map(character => ( | ||
<Chip | ||
key={character.key} | ||
color="primary" | ||
variant="flat" | ||
className="max-w-[6rem]" | ||
classNames={{ | ||
content: "overflow-ellipsis whitespace-nowrap overflow-hidden" | ||
}} | ||
> | ||
{character.data?.name} | ||
</Chip> | ||
))} | ||
</div> | ||
) | ||
}} | ||
> | ||
{(character) => ( | ||
<SelectItem | ||
key={character.id} | ||
value={character.id} | ||
classNames={{ | ||
title: "capitalize" | ||
}} | ||
> | ||
{character.name} | ||
</SelectItem> | ||
)} | ||
</Select> | ||
</Fragment> | ||
) | ||
} | ||
|
||
export default DreamCharacterSelect |
Oops, something went wrong.