Files
portfolio/web/src/components/Project/AdminProject/AdminProject.tsx
2024-10-24 18:14:19 -04:00

176 lines
5.4 KiB
TypeScript

import parseHtml from 'react-html-parser'
import type {
DeleteProjectMutation,
DeleteProjectMutationVariables,
AdminFindProjectById,
} from 'types/graphql'
import { Link, routes, navigate } from '@redwoodjs/router'
import { useMutation } from '@redwoodjs/web'
import type { TypedDocumentNode } from '@redwoodjs/web'
import { toast } from '@redwoodjs/web/toast'
import { calculateLuminance } from 'src/lib/color'
import { timeTag } from 'src/lib/formatters'
import { batchDelete } from 'src/lib/tus'
const DELETE_PROJECT_MUTATION: TypedDocumentNode<
DeleteProjectMutation,
DeleteProjectMutationVariables
> = gql`
mutation DeleteProjectMutation($id: Int!) {
deleteProject(id: $id) {
id
}
}
`
interface Props {
project: NonNullable<AdminFindProjectById['project']>
}
const AdminProject = ({ project }: Props) => {
const [deleteProject] = useMutation(DELETE_PROJECT_MUTATION, {
onCompleted: () => {
toast.success('Project deleted')
navigate(routes.adminProjects())
},
onError: (error) => toast.error(error.message),
})
const onDeleteClick = (id: DeleteProjectMutationVariables['id']) => {
if (confirm('Are you sure you want to delete project ' + id + '?')) {
batchDelete(project.images)
deleteProject({ variables: { id } })
}
}
return (
<div className="flex justify-center">
<div>
<div className="overflow-hidden overflow-x-auto rounded-xl bg-base-100">
<table className="table">
<thead className="bg-base-200 font-syne">
<tr>
<th colSpan={2}>
Project {project.id}: {project.title}
</th>
</tr>
</thead>
<tbody>
<tr>
<th className="text-right">ID</th>
<td>{project.id}</td>
</tr>
<tr>
<th className="text-right">Title</th>
<td>{project.title}</td>
</tr>
<tr>
<th className="text-right">Description</th>
<td>
<article className="prose">
{parseHtml(project.description)}
</article>
</td>
</tr>
<tr>
<th className="text-right">Date</th>
<td>{timeTag(project.date)}</td>
</tr>
<tr>
<th className="text-right">Images</th>
<td>
<div className="flex flex-wrap gap-2">
{project.images.map((image, i) => (
<a
key={i}
href={image}
target="_blank"
className={`btn btn-sm btn-square ${i === 0 && 'btn-primary'}`}
rel="noreferrer"
>
{i + 1}
</a>
))}
</div>
</td>
</tr>
<tr>
<th className="text-right">Tags</th>
<td>
<div className="flex flex-wrap gap-2">
{project.tags.map((tag, i) => (
<div
key={i}
className="badge whitespace-nowrap"
style={{
backgroundColor: tag.color,
color:
calculateLuminance(tag.color) > 0.5
? 'black'
: 'white',
}}
>
{tag.tag}
</div>
))}
</div>
</td>
</tr>
<tr>
<th className="text-right">Links</th>
<td>
<div className="flex flex-wrap gap-2">
{project.links.map((link, i) => (
<>
<a
href={link}
target="_blank"
className="hidden sm:flex badge badge-ghost text-nowrap"
key={i}
rel="noreferrer"
>
{link}
</a>
<a
href={link}
target="_blank"
className="btn btn-sm btn-square sm:hidden"
key={i}
rel="noreferrer"
>
{i + 1}
</a>
</>
))}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<nav className="my-2 flex justify-center space-x-2">
<Link
to={routes.editProject({ id: project.id })}
title={'Edit project ' + project.id}
className="btn btn-primary btn-sm uppercase"
>
Edit
</Link>
<button
type="button"
title={'Delete project ' + project.id}
className="btn btn-error btn-sm uppercase"
onClick={() => onDeleteClick(project.id)}
>
Delete
</button>
</nav>
</div>
</div>
)
}
export default AdminProject