more more more
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import type { CommentDeletionPromptProps, DeletionType } from "~/types/comment";
|
||||
import UserDefaultImage from "~/components/icons/UserDefaultImage";
|
||||
import Xmark from "~/components/icons/Xmark";
|
||||
import Modal from "~/components/ui/Modal";
|
||||
import Button from "~/components/ui/Button";
|
||||
|
||||
export default function CommentDeletionPrompt(
|
||||
props: CommentDeletionPromptProps
|
||||
@@ -44,103 +45,90 @@ export default function CommentDeletionPrompt(
|
||||
normalDeleteChecked() || adminDeleteChecked() || fullDeleteChecked();
|
||||
|
||||
return (
|
||||
<div class="flex justify-center">
|
||||
<div class="fixed top-48 z-100 h-fit">
|
||||
<div
|
||||
id="delete_prompt"
|
||||
class="fade-in bg-red rounded-md px-8 py-4 shadow-lg brightness-110"
|
||||
>
|
||||
<button class="fixed right-4" onClick={() => props.onClose()}>
|
||||
<Xmark strokeWidth={0.5} color="white" height={50} width={50} />
|
||||
</button>
|
||||
<div class="py-4 text-center text-3xl tracking-wide">
|
||||
Comment Deletion
|
||||
</div>
|
||||
<div class="bg-surface0 mx-auto w-3/4 rounded px-6 py-4">
|
||||
<div class="flex overflow-x-auto overflow-y-hidden select-text">
|
||||
{/* Comment body will be passed as prop */}
|
||||
</div>
|
||||
<div class="my-2 flex pl-2">
|
||||
<Show
|
||||
when={props.commenterImage}
|
||||
fallback={
|
||||
<UserDefaultImage strokeWidth={1} height={24} width={24} />
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={props.commenterImage}
|
||||
height={24}
|
||||
width={24}
|
||||
alt="user-image"
|
||||
class="h-6 w-6 rounded-full object-cover object-center"
|
||||
/>
|
||||
</Show>
|
||||
<div class="px-1">
|
||||
{props.commenterDisplayName ||
|
||||
props.commenterEmail ||
|
||||
"[removed]"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex w-full justify-center">
|
||||
<div class="flex pt-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="my-auto"
|
||||
checked={normalDeleteChecked()}
|
||||
onChange={handleNormalDeleteCheckbox}
|
||||
/>
|
||||
<div class="my-auto px-2 text-sm font-normal">
|
||||
{props.privilegeLevel === "admin"
|
||||
? "Confirm User Delete?"
|
||||
: "Confirm Delete?"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={props.privilegeLevel === "admin"}>
|
||||
<div class="flex w-full justify-center">
|
||||
<div class="flex pt-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="my-auto"
|
||||
checked={adminDeleteChecked()}
|
||||
onChange={handleAdminDeleteCheckbox}
|
||||
/>
|
||||
<div class="my-auto px-2 text-sm font-normal">
|
||||
Confirm Admin Delete?
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex w-full justify-center">
|
||||
<div class="flex pt-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="my-auto"
|
||||
checked={fullDeleteChecked()}
|
||||
onChange={handleFullDeleteCheckbox}
|
||||
/>
|
||||
<div class="my-auto px-2 text-sm font-normal">
|
||||
Confirm Full Delete (removal from database)?
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Modal
|
||||
open={props.isOpen}
|
||||
onClose={props.onClose}
|
||||
title="Comment Deletion"
|
||||
class="bg-red brightness-110"
|
||||
>
|
||||
<div class="bg-surface0 mx-auto w-3/4 rounded px-6 py-4">
|
||||
<div class="flex overflow-x-auto overflow-y-hidden select-text">
|
||||
{/* Comment body will be passed as prop */}
|
||||
</div>
|
||||
<div class="my-2 flex pl-2">
|
||||
<Show
|
||||
when={props.commenterImage}
|
||||
fallback={
|
||||
<UserDefaultImage strokeWidth={1} height={24} width={24} />
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={props.commenterImage}
|
||||
height={24}
|
||||
width={24}
|
||||
alt="user-image"
|
||||
class="h-6 w-6 rounded-full object-cover object-center"
|
||||
/>
|
||||
</Show>
|
||||
<div class="flex w-full justify-center pt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={deletionWrapper}
|
||||
disabled={props.commentDeletionLoading || !isDeleteEnabled()}
|
||||
class={`${
|
||||
props.commentDeletionLoading || !isDeleteEnabled()
|
||||
? "bg-surface2 opacity-50"
|
||||
: "border-red bg-red hover:brightness-125"
|
||||
} rounded border px-4 py-2 text-base shadow-md transition-all duration-300 ease-in-out active:scale-90`}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<div class="px-1">
|
||||
{props.commenterDisplayName || props.commenterEmail || "[removed]"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex w-full justify-center">
|
||||
<div class="flex pt-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="my-auto"
|
||||
checked={normalDeleteChecked()}
|
||||
onChange={handleNormalDeleteCheckbox}
|
||||
/>
|
||||
<div class="my-auto px-2 text-sm font-normal">
|
||||
{props.privilegeLevel === "admin"
|
||||
? "Confirm User Delete?"
|
||||
: "Confirm Delete?"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={props.privilegeLevel === "admin"}>
|
||||
<div class="flex w-full justify-center">
|
||||
<div class="flex pt-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="my-auto"
|
||||
checked={adminDeleteChecked()}
|
||||
onChange={handleAdminDeleteCheckbox}
|
||||
/>
|
||||
<div class="my-auto px-2 text-sm font-normal">
|
||||
Confirm Admin Delete?
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex w-full justify-center">
|
||||
<div class="flex pt-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="my-auto"
|
||||
checked={fullDeleteChecked()}
|
||||
onChange={handleFullDeleteCheckbox}
|
||||
/>
|
||||
<div class="my-auto px-2 text-sm font-normal">
|
||||
Confirm Full Delete (removal from database)?
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
<div class="flex w-full justify-center pt-2">
|
||||
<Button
|
||||
type="button"
|
||||
onClick={deletionWrapper}
|
||||
loading={props.commentDeletionLoading}
|
||||
disabled={!isDeleteEnabled()}
|
||||
variant="danger"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -634,42 +634,36 @@ export default function CommentSectionWrapper(
|
||||
commentReaction={commentReaction}
|
||||
/>
|
||||
|
||||
<Show when={showingDeletionPrompt()}>
|
||||
<div ref={deletePromptRef}>
|
||||
<CommentDeletionPrompt
|
||||
commentID={commentIDForModification()}
|
||||
commenterID={commenterForModification()}
|
||||
commenterImage={commenterImageForModification()}
|
||||
commenterEmail={commenterEmailForModification()}
|
||||
commenterDisplayName={commenterDisplayNameForModification()}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
commentDeletionLoading={commentDeletionLoading()}
|
||||
deleteComment={deleteComment}
|
||||
onClose={() => {
|
||||
setShowingDeletionPrompt(false);
|
||||
clearModificationPrompt();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<CommentDeletionPrompt
|
||||
isOpen={showingDeletionPrompt()}
|
||||
commentID={commentIDForModification()}
|
||||
commenterID={commenterForModification()}
|
||||
commenterImage={commenterImageForModification()}
|
||||
commenterEmail={commenterEmailForModification()}
|
||||
commenterDisplayName={commenterDisplayNameForModification()}
|
||||
privilegeLevel={props.privilegeLevel}
|
||||
commentDeletionLoading={commentDeletionLoading()}
|
||||
deleteComment={deleteComment}
|
||||
onClose={() => {
|
||||
setShowingDeletionPrompt(false);
|
||||
clearModificationPrompt();
|
||||
}}
|
||||
/>
|
||||
|
||||
<Show when={showingCommentEdit()}>
|
||||
<div ref={modificationPromptRef}>
|
||||
<EditCommentModal
|
||||
commentID={commentIDForModification()}
|
||||
commentBody={commentBodyForModification()}
|
||||
commenterImage={commenterImageForModification()}
|
||||
commenterEmail={commenterEmailForModification()}
|
||||
commenterDisplayName={commenterDisplayNameForModification()}
|
||||
editCommentLoading={editCommentLoading()}
|
||||
editComment={editComment}
|
||||
onClose={() => {
|
||||
setShowingCommentEdit(false);
|
||||
clearModificationPrompt();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<EditCommentModal
|
||||
isOpen={showingCommentEdit()}
|
||||
commentID={commentIDForModification()}
|
||||
commentBody={commentBodyForModification()}
|
||||
commenterImage={commenterImageForModification()}
|
||||
commenterEmail={commenterEmailForModification()}
|
||||
commenterDisplayName={commenterDisplayNameForModification()}
|
||||
editCommentLoading={editCommentLoading()}
|
||||
editComment={editComment}
|
||||
onClose={() => {
|
||||
setShowingCommentEdit(false);
|
||||
clearModificationPrompt();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import type { EditCommentModalProps } from "~/types/comment";
|
||||
import Xmark from "~/components/icons/Xmark";
|
||||
import Modal from "~/components/ui/Modal";
|
||||
import Button from "~/components/ui/Button";
|
||||
|
||||
export default function EditCommentModal(props: EditCommentModalProps) {
|
||||
@@ -22,51 +22,38 @@ export default function EditCommentModal(props: EditCommentModalProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="z-100 flex justify-center">
|
||||
<div class="fixed top-48 h-fit w-11/12 sm:w-4/5 md:w-2/3">
|
||||
<div
|
||||
id="edit_prompt"
|
||||
class="fade-in bg-surface1 z-50 rounded-md px-8 py-4 shadow-lg"
|
||||
>
|
||||
<button class="absolute right-4" onClick={() => props.onClose()}>
|
||||
<Xmark
|
||||
strokeWidth={0.5}
|
||||
color="var(--color-text)"
|
||||
height={50}
|
||||
width={50}
|
||||
/>
|
||||
</button>
|
||||
<div class="text-text py-4 text-center text-3xl tracking-wide">
|
||||
Edit Comment
|
||||
</div>
|
||||
<form onSubmit={editCommentWrapper}>
|
||||
<div class="textarea-group home">
|
||||
<textarea
|
||||
required
|
||||
ref={bodyRef}
|
||||
placeholder=" "
|
||||
value={props.commentBody}
|
||||
class="underlinedInput text-blue w-full bg-transparent"
|
||||
rows={4}
|
||||
/>
|
||||
<span class="bar" />
|
||||
<label class="underlinedInputLabel">Edit Comment</label>
|
||||
</div>
|
||||
<div class="flex justify-end pt-2">
|
||||
<Button
|
||||
type="submit"
|
||||
loading={props.editCommentLoading}
|
||||
variant="primary"
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<Show when={showNoChange()}>
|
||||
<div class="text-red text-center italic">No change detected</div>
|
||||
</Show>
|
||||
<Modal
|
||||
open={props.isOpen}
|
||||
onClose={props.onClose}
|
||||
title="Edit Comment"
|
||||
class="bg-surface1 w-11/12 max-w-none sm:w-4/5 md:w-2/3"
|
||||
>
|
||||
<form onSubmit={editCommentWrapper}>
|
||||
<div class="textarea-group home">
|
||||
<textarea
|
||||
required
|
||||
ref={bodyRef}
|
||||
placeholder=" "
|
||||
value={props.commentBody}
|
||||
class="underlinedInput text-blue w-full bg-transparent"
|
||||
rows={4}
|
||||
/>
|
||||
<span class="bar" />
|
||||
<label class="underlinedInputLabel">Edit Comment</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end pt-2">
|
||||
<Button
|
||||
type="submit"
|
||||
loading={props.editCommentLoading}
|
||||
variant="primary"
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<Show when={showNoChange()}>
|
||||
<div class="text-red text-center italic">No change detected</div>
|
||||
</Show>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
87
src/components/ui/Modal.tsx
Normal file
87
src/components/ui/Modal.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Show, onMount, onCleanup, type JSX } from "solid-js";
|
||||
import { Portal } from "solid-js/web";
|
||||
import Xmark from "~/components/icons/Xmark";
|
||||
|
||||
export interface ModalProps {
|
||||
/** Controls modal visibility */
|
||||
open: boolean;
|
||||
/** Callback when modal should close */
|
||||
onClose: () => void;
|
||||
/** Modal title (optional) */
|
||||
title?: string | JSX.Element;
|
||||
/** Modal content */
|
||||
children: JSX.Element;
|
||||
/** Action buttons (optional) */
|
||||
actions?: JSX.Element;
|
||||
/** Additional CSS classes for modal container */
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export default function Modal(props: ModalProps) {
|
||||
const handleBackdropClick = (e: MouseEvent) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
props.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const handleEscapeKey = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
props.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
if (props.open) {
|
||||
document.addEventListener("keydown", handleEscapeKey);
|
||||
}
|
||||
});
|
||||
|
||||
onCleanup(() => {
|
||||
document.removeEventListener("keydown", handleEscapeKey);
|
||||
});
|
||||
|
||||
return (
|
||||
<Show when={props.open}>
|
||||
<Portal>
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
|
||||
onClick={handleBackdropClick}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<div
|
||||
class={`bg-base fade-in relative mx-4 max-w-md rounded-md px-8 py-4 shadow-lg ${props.class || ""}`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
class="absolute top-4 right-4"
|
||||
onClick={props.onClose}
|
||||
aria-label="Close modal"
|
||||
>
|
||||
<Xmark
|
||||
strokeWidth={0.5}
|
||||
color="var(--color-text)"
|
||||
height={50}
|
||||
width={50}
|
||||
/>
|
||||
</button>
|
||||
|
||||
<Show when={props.title}>
|
||||
<div class="py-4 text-center text-3xl tracking-wide">
|
||||
{props.title}
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class="modal-content">{props.children}</div>
|
||||
|
||||
<Show when={props.actions}>
|
||||
<div class="modal-actions">{props.actions}</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</Portal>
|
||||
</Show>
|
||||
);
|
||||
}
|
||||
|
||||
export { Modal };
|
||||
@@ -176,6 +176,7 @@ export interface ReactionBarProps {
|
||||
}
|
||||
|
||||
export interface CommentDeletionPromptProps {
|
||||
isOpen: boolean;
|
||||
privilegeLevel: PrivilegeLevel;
|
||||
commentID: number;
|
||||
commenterID: string;
|
||||
@@ -192,6 +193,7 @@ export interface CommentDeletionPromptProps {
|
||||
}
|
||||
|
||||
export interface EditCommentModalProps {
|
||||
isOpen: boolean;
|
||||
commentID: number;
|
||||
commentBody: string;
|
||||
editComment: (body: string, comment_id: number) => Promise<void>;
|
||||
|
||||
Reference in New Issue
Block a user