Compare commits
15 Commits
Author | SHA1 | Date |
---|---|---|
|
e66ed6975d | |
|
872c1fd53a | |
|
c8c29fab75 | |
|
4459b9d644 | |
|
ae4e1685c5 | |
|
c0f85e89fd | |
|
f939c3896a | |
|
39ba6901d1 | |
|
e2b21601ea | |
|
59a8f8bc41 | |
|
01b98a0a08 | |
|
3c3564bb29 | |
|
cda903175c | |
|
e1044b58b7 | |
|
a5c40a7982 |
|
@ -11,12 +11,13 @@ agent any
|
|||
sh 'echo "DATABASE_URL=${DATABASE_URL}" | cat >> .env'
|
||||
sh 'npm install'
|
||||
sh 'npm run build'
|
||||
sh 'rm -r pack'
|
||||
}
|
||||
}
|
||||
stage('test'){
|
||||
steps{
|
||||
sh 'npx playwright install'
|
||||
sh 'npx playwright test'
|
||||
sh 'rm -r pack'
|
||||
}
|
||||
}
|
||||
stage('deploy'){
|
||||
|
@ -29,6 +30,7 @@ agent any
|
|||
// Clean after build
|
||||
always {
|
||||
cleanWs(cleanWhenNotBuilt: true,
|
||||
cleanWhenFailure: false,
|
||||
deleteDirs: true,
|
||||
disableDeferredWipeout: true,
|
||||
// notFailBuild: true,
|
||||
|
|
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
|
@ -44,7 +44,7 @@ export default function LoginForm() {
|
|||
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="flex flex-col items-center justify-around h-60 w-26">
|
||||
{submitted ? <div className="flex flex-col items-center justify-around h-30 w-26">
|
||||
<h1>Logging in...</h1>
|
||||
<Button asChild>
|
||||
|
@ -52,7 +52,7 @@ export default function LoginForm() {
|
|||
</Button>
|
||||
</div> :
|
||||
<Form {...form}>
|
||||
<form onSubmit={onSubmit} className="mt-20 flex flex-col items-center space-y-6">
|
||||
<form onSubmit={onSubmit} className="flex flex-col items-center space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
|
@ -83,7 +83,7 @@ export default function LoginForm() {
|
|||
</form>
|
||||
</Form>
|
||||
}
|
||||
</>
|
||||
</main>
|
||||
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,21 +3,21 @@ import { Button } from "@/components/ui/button";
|
|||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex flex-col items-center justify-around h-60 w-26">
|
||||
<main className="flex flex-col gap-4 items-center justify-around h-60 w-26 m-6">
|
||||
< div >
|
||||
<h1 className="text-3xl font-black">
|
||||
Welcome to Subman
|
||||
Welcome to Subman!
|
||||
</h1>
|
||||
</div >
|
||||
<div>
|
||||
<p className="mb-6">
|
||||
<div className="flex flex-col gap-3">
|
||||
<p>
|
||||
This app is for demonstration purposes only. Data is reset periodically.
|
||||
</p>
|
||||
<p>
|
||||
USERNAME: demo@demo.demo
|
||||
<b>USERNAME:</b> demo@demo.demo
|
||||
</p>
|
||||
<p>
|
||||
PASSWORD: password
|
||||
<b>PASSWORD:</b> password
|
||||
</p>
|
||||
</div>
|
||||
<Button className="mt-6">
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
"use client"
|
||||
import { Dialog, DialogHeader, DialogTrigger, DialogContent, DialogClose, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
|
||||
import { DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ComponentProps } from "react";
|
||||
import { Genre, Pub } from "@prisma/client";
|
||||
import { createPub } from "app/lib/create";
|
||||
import PubForm from "app/ui/forms/pub";
|
||||
import { Plus } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { PubWithGenres } from "./page";
|
||||
|
||||
export default function EditPubDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: PubWithGenres, dbAction: (data: Pub & { genres: number[] }) => Promise<{ success: string }> }) {
|
||||
|
@ -17,7 +14,7 @@ export default function EditPubDialog({ genres, closeDialog, defaults, dbAction
|
|||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit publication</DialogTitle>
|
||||
<DialogDescription>Modify an entry for an existing publication.</DialogDescription>
|
||||
<DialogDescription>Modify an entry for an existing publication. Remember - you can edit fields inline by double clicking on them!</DialogDescription>
|
||||
</DialogHeader>
|
||||
<PubForm dbAction={dbAction} genres={genres} closeDialog={closeDialog} defaults={defaults} />
|
||||
<DialogFooter>
|
||||
|
|
|
@ -14,7 +14,7 @@ export default function EditStoryDialog({ genres, closeDialog, defaults, dbActio
|
|||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit story</DialogTitle>
|
||||
<DialogDescription>Create an entry for a new story i.e. a thing you intend to submit for publication.</DialogDescription>
|
||||
<DialogDescription>Modify an entry for an existing story. Remember - you can edit fields inline by double-clicking on them!</DialogDescription>
|
||||
</DialogHeader>
|
||||
<StoryForm dbAction={dbAction} genres={genres} className="" closeDialog={closeDialog} defaults={defaults} />
|
||||
<DialogFooter>
|
||||
|
|
|
@ -5,7 +5,6 @@ import { Button } from "@/components/ui/button"
|
|||
import { SubComplete } from "./page"
|
||||
import { selectCol } from "app/ui/tables/selectColumn"
|
||||
import TitleContainer from "app/ui/titleContainer"
|
||||
import { CalendarArrowUp } from "lucide"
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@ import { Pub, Response, Story } from "@prisma/client";
|
|||
import SubmissionForm from "app/ui/forms/sub";
|
||||
import { Plus } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { StoryWithGenres } from "app/story/page";
|
||||
import { PubWithGenres } from "app/publication/page";
|
||||
|
||||
|
||||
|
||||
export default function CreateSubmissionDialog({ stories, pubs, responses }: ComponentProps<"div"> & { stories: Story[], pubs: Pub[], responses: Response[] }) {
|
||||
export default function CreateSubmissionDialog({ stories, pubs, responses }: ComponentProps<"div"> & { stories: StoryWithGenres[], pubs: PubWithGenres[], responses: Response[] }) {
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
function closeDialog() {
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
"use server"
|
||||
import { getPubs, getResponses, getStories } from "app/lib/get";
|
||||
import SubmissionForm from "app/ui/forms/sub";
|
||||
import prisma from "app/lib/db";
|
||||
import { CreateContainer, CreateContainerContent, CreateContainerHeader } from "app/ui/createContainer";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Page() {
|
||||
const stories = await getStories()
|
||||
const pubs = await getPubs()
|
||||
const responses = await getResponses()
|
||||
|
||||
return (
|
||||
<CreateContainer>
|
||||
<CreateContainerHeader>New submission</CreateContainerHeader>
|
||||
<CreateContainerContent>
|
||||
<SubmissionForm stories={stories} pubs={pubs} responses={responses} />
|
||||
</CreateContainerContent>
|
||||
</CreateContainer>
|
||||
)
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
import { getGenres, getPubs, getResponses, getStories, getSubsComplete } from "app/lib/get"
|
||||
import { getGenres, getPubs, getPubsWithGenres, getResponses, getStories, getStoriesWithGenres, getSubsComplete } from "app/lib/get"
|
||||
import { DataTable } from "app/ui/tables/data-table"
|
||||
import { columns } from "./columns"
|
||||
import { Pub, Response, Story, Sub } from "@prisma/client"
|
||||
import { Genre, Pub, Response, Story, Sub } from "@prisma/client"
|
||||
import CreateSubmissionDialog from "./create"
|
||||
import { PubWithGenres } from "app/publication/page"
|
||||
import { StoryWithGenres } from "app/story/page"
|
||||
|
||||
export type SubComplete = Sub & {
|
||||
pub: Pub,
|
||||
|
@ -12,10 +14,10 @@ export type SubComplete = Sub & {
|
|||
export default async function Page() {
|
||||
|
||||
const subs: Array<SubComplete> = await getSubsComplete()
|
||||
const stories = await getStories()
|
||||
const pubs = await getPubs()
|
||||
const responses = await getResponses()
|
||||
const genres = await getGenres()
|
||||
const stories: StoryWithGenres[] = await getStoriesWithGenres()
|
||||
const pubs: PubWithGenres[] = await getPubsWithGenres()
|
||||
const responses: Response[] = await getResponses()
|
||||
const genres: Genre[] = await getGenres()
|
||||
|
||||
return (
|
||||
<div className="container px-1 md:px-4 mx-auto">
|
||||
|
|
|
@ -706,6 +706,10 @@ body {
|
|||
z-index: 100;
|
||||
}
|
||||
|
||||
.m-6 {
|
||||
margin: 1.5rem;
|
||||
}
|
||||
|
||||
.m-auto {
|
||||
margin: auto;
|
||||
}
|
||||
|
@ -715,6 +719,11 @@ body {
|
|||
margin-right: -0.25rem;
|
||||
}
|
||||
|
||||
.mx-0 {
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.mx-1 {
|
||||
margin-left: 0.25rem;
|
||||
margin-right: 0.25rem;
|
||||
|
@ -765,10 +774,6 @@ body {
|
|||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-20 {
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
.mt-3 {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
@ -781,10 +786,6 @@ body {
|
|||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.mb-6 {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
@ -854,6 +855,10 @@ body {
|
|||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.h-60 {
|
||||
height: 15rem;
|
||||
}
|
||||
|
||||
.h-7 {
|
||||
height: 1.75rem;
|
||||
}
|
||||
|
@ -887,10 +892,6 @@ body {
|
|||
height: 100vh;
|
||||
}
|
||||
|
||||
.h-60 {
|
||||
height: 15rem;
|
||||
}
|
||||
|
||||
.max-h-96 {
|
||||
max-height: 24rem;
|
||||
}
|
||||
|
@ -976,14 +977,6 @@ body {
|
|||
width: 100vw;
|
||||
}
|
||||
|
||||
.w-14 {
|
||||
width: 3.5rem;
|
||||
}
|
||||
|
||||
.w-20 {
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.min-w-\[8rem\] {
|
||||
min-width: 8rem;
|
||||
}
|
||||
|
@ -1141,10 +1134,6 @@ body {
|
|||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.justify-items-center {
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
.gap-1 {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
@ -1153,6 +1142,10 @@ body {
|
|||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.gap-3 {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
@ -1632,10 +1625,6 @@ body {
|
|||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.underline-offset-4 {
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
|
|
@ -36,12 +36,14 @@ import { createSub } from "app/lib/create"
|
|||
import { subSchema } from "./schemas"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { Ban } from "lucide-react"
|
||||
import { Story } from "@prisma/client"
|
||||
import { Pub, Response, Story, Sub } from "@prisma/client"
|
||||
import { StoryWithGenres } from "app/story/page"
|
||||
import { PubWithGenres } from "app/publication/page"
|
||||
|
||||
export type SubForm = z.infer<typeof subSchema>
|
||||
|
||||
|
||||
export default function SubmissionForm({ stories, pubs, responses, defaults, closeDialog }: { stories: any, pubs: any, responses: any, defaults?: any, closeDialog?: () => void }) {
|
||||
export default function SubmissionForm({ stories, pubs, responses, defaults, closeDialog }: { stories: StoryWithGenres[], pubs: PubWithGenres[], responses: Response[], defaults?: Sub, closeDialog?: () => void }) {
|
||||
const form = useForm<z.infer<typeof subSchema>>({
|
||||
resolver: zodResolver(subSchema),
|
||||
defaultValues: {
|
||||
|
@ -51,19 +53,41 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo
|
|||
})
|
||||
const [isSubCalendarOpen, setIsSubCalendarOpen] = useState(false);
|
||||
const [isRespCalendarOpen, setIsRespCalendarOpen] = useState(false);
|
||||
const [relevantPubIds, setRelevantPubIds] = useState(pubs.map(e => e.id));
|
||||
|
||||
function updateRelevantPubs(storyId: number) {
|
||||
console.log("storyId: " + storyId)
|
||||
console.log("stories: ", stories)
|
||||
const story = stories.find(e => e.id == storyId)
|
||||
console.log("story: ", story)
|
||||
const storyGenreIds = story?.genres.map(e => e.id) ?? []
|
||||
const relevantPubIds = pubs.filter(e => {
|
||||
const pubGenreIds = e.genres.map(e => e.id)
|
||||
for (let i = 0; i < storyGenreIds.length; i++) {
|
||||
const storyGenreId = storyGenreIds[i];
|
||||
if (pubGenreIds.includes(storyGenreId)) return true
|
||||
}
|
||||
}).map(e => e.id)
|
||||
console.log("relevant pubs: ", relevantPubIds)
|
||||
setRelevantPubIds(relevantPubIds)
|
||||
}
|
||||
|
||||
const storiesSelectItems = stories.map((e: Story) => (
|
||||
<SelectItem value={e.id?.toString()} key={e.title}>
|
||||
{e.title}
|
||||
</SelectItem>
|
||||
))
|
||||
const pubsSelectItems = pubs.map(e => (
|
||||
<SelectItem value={e.id} key={e.title}>
|
||||
{e.title}
|
||||
</SelectItem>
|
||||
))
|
||||
const pubsSelectItems = pubs.map(e => {
|
||||
const isDisabled = !relevantPubIds.includes(e.id)
|
||||
return (
|
||||
<SelectItem disabled={isDisabled} value={e.id.toString()} key={e.title}>
|
||||
{e.title}
|
||||
</SelectItem>
|
||||
)
|
||||
})
|
||||
|
||||
const reponsesSelectItems = responses.map(e => (
|
||||
<SelectItem value={e.id} key={e.title}>
|
||||
<SelectItem value={e.id.toString()} key={e.response}>
|
||||
{e.response}
|
||||
</SelectItem>
|
||||
))
|
||||
|
@ -127,7 +151,8 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo
|
|||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-sm md:text-base">Publication</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value?.toString()}>
|
||||
<Select onOpenChange={() => updateRelevantPubs(form.getValues().storyId
|
||||
)} onValueChange={field.onChange} defaultValue={field.value?.toString()}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select something">
|
||||
|
@ -139,7 +164,7 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo
|
|||
{pubsSelectItems}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription className="text-xs md:text-base">The market you sent it to</FormDescription>
|
||||
<FormDescription className="text-xs md:text-base">The market you sent it to. Bad genre fits are greyed out.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuContent,
|
||||
ContextMenuItem,
|
||||
ContextMenuTrigger,
|
||||
} from "@/components/ui/context-menu"
|
||||
import {
|
||||
|
@ -15,7 +13,7 @@ import {
|
|||
DropdownMenuRadioGroup
|
||||
} from "@/components/ui/dropdown-menu"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Component, ComponentProps, use, useState } from "react"
|
||||
import { ComponentProps, useState } from "react"
|
||||
import {
|
||||
ColumnDef,
|
||||
flexRender,
|
||||
|
@ -38,7 +36,7 @@ import {
|
|||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { EyeIcon, Trash2 } from "lucide-react"
|
||||
import { CircleHelp, EyeIcon, Filter, Trash2 } from "lucide-react"
|
||||
import { usePathname, useSearchParams } from "next/navigation"
|
||||
import FormContextMenu from "./contextMenu"
|
||||
import { deleteRecord, deleteRecords } from "app/lib/del"
|
||||
|
@ -129,16 +127,14 @@ export function DataTable<TData, TValue>({
|
|||
|
||||
const router = useRouter()
|
||||
|
||||
const [filterBy, setFilterBy] = useState(table.getAllColumns()[0])
|
||||
const [filterBy, setFilterBy] = useState(table.getAllColumns().filter(e => e.getCanFilter())[0])
|
||||
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false)
|
||||
return (<>
|
||||
<div className="flex justify-between items-center py-1 md:py-4">
|
||||
<div className="flex gap-2">
|
||||
<div className="flex gap-2 justify-between items-center py-1 md:py-4">
|
||||
<div className="flex gap-1">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" className="hidden sm:block ml-auto">
|
||||
Filter by
|
||||
</Button>
|
||||
<Button variant="outline" className="mx-0"> <p className="hidden md:block">Filter by</p><Filter className="block md:hidden" /> </Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
{/*@ts-ignore*/}
|
||||
|
@ -308,36 +304,45 @@ export function DataTable<TData, TValue>({
|
|||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<ContextMenu key={row.id + "contextMenu"}>
|
||||
<ContextMenuTrigger asChild>
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
tabIndex={0}
|
||||
onDoubleClick={() => {
|
||||
if (tableName === "sub") {
|
||||
openEditDialog(row)
|
||||
table.getRowModel().rows.map((row) => {
|
||||
const classes = () => {
|
||||
const classes = []
|
||||
if (row.getValue('response') === "Pending") classes.push("bg-accent")
|
||||
if (row.getValue('response') === "Acceptance") classes.push("bg-primary")
|
||||
return classes.join(" ")
|
||||
}
|
||||
return (
|
||||
<ContextMenu key={row.id + "contextMenu"}>
|
||||
<ContextMenuTrigger asChild>
|
||||
<TableRow
|
||||
key={row.id}
|
||||
className={classes()}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
tabIndex={0}
|
||||
onDoubleClick={() => {
|
||||
if (tableName === "sub") {
|
||||
openEditDialog(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
<FormContextMenu
|
||||
key={"formContextMenu" + row.id}
|
||||
row={row}
|
||||
table={table}
|
||||
openEditDialog={openEditDialog}
|
||||
openDeleteDialog={openDeleteDialog}
|
||||
/>
|
||||
</TableRow>
|
||||
</ContextMenuTrigger>
|
||||
</ContextMenu>
|
||||
))
|
||||
}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
<FormContextMenu
|
||||
key={"formContextMenu" + row.id}
|
||||
row={row}
|
||||
table={table}
|
||||
openEditDialog={openEditDialog}
|
||||
openDeleteDialog={openDeleteDialog}
|
||||
/>
|
||||
</TableRow>
|
||||
</ContextMenuTrigger>
|
||||
</ContextMenu>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
|
|
|
@ -16,7 +16,7 @@ export const selectCol = {
|
|||
|
||||
)
|
||||
},
|
||||
|
||||
enableColumnFilter: false,
|
||||
cell: (props: CellContext<any, any>) => {
|
||||
return (
|
||||
<div className="flex items-start justify-left">
|
||||
|
|
Loading…
Reference in New Issue