feat: implement file upload functionality and enhance admin dashboard layout
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
|
||||
/**
|
||||
* Note: `ChevronDoubleIcon` default mengarah ke kiri.
|
||||
* Gunakan class `rotate-xx` untuk mengubah arah ikon.
|
||||
*/
|
||||
export const ChevronDoubleIcon = (
|
||||
properties: JSX.IntrinsicAttributes & SVGProps<SVGSVGElement>,
|
||||
) => {
|
||||
return (
|
||||
<svg
|
||||
width={20}
|
||||
height={20}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={properties.className}
|
||||
{...properties}
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12.512 4.427l-2.984 3.58 2.877 3.575a.667.667 0 01-1.04.836l-3.218-4a.667.667 0 01.007-.844l3.334-4a.667.667 0 011.024.853zm-5.69-.853a.667.667 0 011.023.853l-2.984 3.58 2.877 3.575a.667.667 0 01-1.039.836l-3.218-4a.666.666 0 01.007-.844l3.333-4z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Field, Label, Input as HeadlessInput } from '@headlessui/react'
|
||||
import { CloudArrowUpIcon } from '@heroicons/react/20/solid'
|
||||
import { type ComponentProps, type ReactNode } from 'react'
|
||||
import { useEffect, type ComponentProps, type ReactNode } from 'react'
|
||||
import {
|
||||
get,
|
||||
type FieldError,
|
||||
@@ -42,15 +42,23 @@ export const InputFile = <TFormValues extends Record<string, unknown>>(
|
||||
labelClassName,
|
||||
...restProperties
|
||||
} = properties
|
||||
const { setIsUploadOpen } = useAdminContext()
|
||||
const { setIsUploadOpen, uploadedFile } = useAdminContext()
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
} = useRemixFormContext()
|
||||
|
||||
const error: FieldError = get(errors, name)
|
||||
|
||||
useEffect(() => {
|
||||
if (uploadedFile) {
|
||||
setValue('featured_image', uploadedFile)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [uploadedFile])
|
||||
|
||||
return (
|
||||
<Field
|
||||
className={twMerge('relative', containerClassName)}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import { ChevronIcon } from '~/components/icons/chevron'
|
||||
import { ChevronDoubleIcon } from '~/components/icons/chevron-double'
|
||||
|
||||
type PaginationProperties = {
|
||||
currentPage: number
|
||||
totalPages: number
|
||||
onPageChange: (page: number) => void
|
||||
}
|
||||
|
||||
export const Pagination: React.FC<PaginationProperties> = ({
|
||||
currentPage = 1,
|
||||
totalPages,
|
||||
onPageChange,
|
||||
}) => {
|
||||
const renderPageNumbers = () => {
|
||||
const pages = []
|
||||
for (let index = 1; index <= totalPages; index++) {
|
||||
pages.push(
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => onPageChange(index)}
|
||||
className={`rounded-lg px-3 py-1 ${
|
||||
currentPage === index ? 'bg-[#2E2F7C] text-white' : 'text-gray-500'
|
||||
}`}
|
||||
>
|
||||
{index}
|
||||
</button>,
|
||||
)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center space-x-2 text-[#2E2F7C]">
|
||||
<button
|
||||
onClick={() => onPageChange(1)}
|
||||
disabled={currentPage === 1}
|
||||
>
|
||||
<ChevronDoubleIcon />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onPageChange(currentPage - 1)}
|
||||
disabled={currentPage === 1}
|
||||
>
|
||||
<ChevronIcon className="rotate-90" />
|
||||
</button>
|
||||
|
||||
{renderPageNumbers()}
|
||||
|
||||
<button
|
||||
onClick={() => onPageChange(currentPage + 1)}
|
||||
disabled={currentPage === totalPages}
|
||||
>
|
||||
<ChevronIcon className="rotate-270" />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onPageChange(totalPages)}
|
||||
disabled={currentPage === totalPages}
|
||||
>
|
||||
<ChevronDoubleIcon className="rotate-180" />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user