ReviewDB: Add Review Modal & Pagination (#1174)
Co-authored-by: V <vendicated@riseup.net>
This commit is contained in:
@ -16,42 +16,113 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/Settings";
|
||||
import { classes } from "@utils/misc";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { useAwaiter, useForceUpdater } from "@utils/react";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Forms, React, Text, UserStore } from "@webpack/common";
|
||||
import { Forms, React, UserStore } from "@webpack/common";
|
||||
import type { KeyboardEvent } from "react";
|
||||
|
||||
import { addReview, getReviews } from "../Utils/ReviewDBAPI";
|
||||
import { authorize, showToast } from "../Utils/Utils";
|
||||
import { Review } from "../entities";
|
||||
import { addReview, getReviews, Response, REVIEWS_PER_PAGE } from "../reviewDbApi";
|
||||
import { settings } from "../settings";
|
||||
import { authorize, cl, showToast } from "../utils";
|
||||
import ReviewComponent from "./ReviewComponent";
|
||||
|
||||
const Classes = findByPropsLazy("inputDefault", "editable");
|
||||
|
||||
export default function ReviewsView({ userId }: { userId: string; }) {
|
||||
const { token } = Settings.plugins.ReviewDB;
|
||||
const [refetchCount, setRefetchCount] = React.useState(0);
|
||||
const [reviews, _, isLoading] = useAwaiter(() => getReviews(userId), {
|
||||
fallbackValue: [],
|
||||
deps: [refetchCount],
|
||||
interface UserProps {
|
||||
discordId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Props extends UserProps {
|
||||
onFetchReviews(data: Response): void;
|
||||
refetchSignal?: unknown;
|
||||
showInput?: boolean;
|
||||
page?: number;
|
||||
scrollToTop?(): void;
|
||||
hideOwnReview?: boolean;
|
||||
}
|
||||
|
||||
export default function ReviewsView({
|
||||
discordId,
|
||||
name,
|
||||
onFetchReviews,
|
||||
refetchSignal,
|
||||
scrollToTop,
|
||||
page = 1,
|
||||
showInput = false,
|
||||
hideOwnReview = false,
|
||||
}: Props) {
|
||||
const [signal, refetch] = useForceUpdater(true);
|
||||
|
||||
const [reviewData] = useAwaiter(() => getReviews(discordId, (page - 1) * REVIEWS_PER_PAGE), {
|
||||
fallbackValue: null,
|
||||
deps: [refetchSignal, signal, page],
|
||||
onSuccess: data => {
|
||||
scrollToTop?.();
|
||||
onFetchReviews(data!);
|
||||
}
|
||||
});
|
||||
const username = UserStore.getUser(userId)?.username ?? "";
|
||||
|
||||
const dirtyRefetch = () => setRefetchCount(refetchCount + 1);
|
||||
if (!reviewData) return null;
|
||||
|
||||
if (isLoading) return null;
|
||||
return (
|
||||
<>
|
||||
<ReviewList
|
||||
refetch={refetch}
|
||||
reviews={reviewData!.reviews}
|
||||
hideOwnReview={hideOwnReview}
|
||||
/>
|
||||
|
||||
{showInput && (
|
||||
<ReviewsInputComponent
|
||||
name={name}
|
||||
discordId={discordId}
|
||||
refetch={refetch}
|
||||
isAuthor={reviewData!.reviews?.some(r => r.sender.discordID === UserStore.getCurrentUser().id)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function ReviewList({ refetch, reviews, hideOwnReview }: { refetch(): void; reviews: Review[]; hideOwnReview: boolean; }) {
|
||||
const myId = UserStore.getCurrentUser().id;
|
||||
|
||||
return (
|
||||
<div className={cl("view")}>
|
||||
{reviews?.map(review =>
|
||||
(review.sender.discordID !== myId || !hideOwnReview) &&
|
||||
<ReviewComponent
|
||||
key={review.id}
|
||||
review={review}
|
||||
refetch={refetch}
|
||||
/>
|
||||
)}
|
||||
|
||||
{reviews?.length === 0 && (
|
||||
<Forms.FormText className={cl("placeholder")}>
|
||||
Looks like nobody reviewed this user yet. You could be the first!
|
||||
</Forms.FormText>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ReviewsInputComponent({ discordId, isAuthor, refetch, name }: { discordId: string, name: string; isAuthor: boolean; refetch(): void; }) {
|
||||
const { token } = settings.store;
|
||||
|
||||
function onKeyPress({ key, target }: KeyboardEvent<HTMLTextAreaElement>) {
|
||||
if (key === "Enter") {
|
||||
addReview({
|
||||
userid: userId,
|
||||
userid: discordId,
|
||||
comment: (target as HTMLInputElement).value,
|
||||
star: -1
|
||||
}).then(res => {
|
||||
if (res?.success) {
|
||||
(target as HTMLInputElement).value = ""; // clear the input
|
||||
dirtyRefetch();
|
||||
refetch();
|
||||
} else if (res?.message) {
|
||||
showToast(res.message);
|
||||
}
|
||||
@ -60,61 +131,27 @@ export default function ReviewsView({ userId }: { userId: string; }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="vc-reviewdb-view">
|
||||
<Text
|
||||
tag="h2"
|
||||
variant="eyebrow"
|
||||
style={{
|
||||
marginBottom: "8px",
|
||||
color: "var(--header-primary)"
|
||||
}}
|
||||
>
|
||||
User Reviews
|
||||
</Text>
|
||||
{reviews?.map(review =>
|
||||
<ReviewComponent
|
||||
key={review.id}
|
||||
review={review}
|
||||
refetch={dirtyRefetch}
|
||||
/>
|
||||
)}
|
||||
{reviews?.length === 0 && (
|
||||
<Forms.FormText style={{ paddingRight: "12px", paddingTop: "0px", paddingLeft: "0px", paddingBottom: "4px", fontWeight: "bold", fontStyle: "italic" }}>
|
||||
Looks like nobody reviewed this user yet. You could be the first!
|
||||
</Forms.FormText>
|
||||
)}
|
||||
<textarea
|
||||
className={classes(Classes.inputDefault, "enter-comment")}
|
||||
onKeyDownCapture={e => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault(); // prevent newlines
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
token
|
||||
? (reviews?.some(r => r.sender.discordID === UserStore.getCurrentUser().id)
|
||||
? `Update review for @${username}`
|
||||
: `Review @${username}`)
|
||||
: "You need to authorize to review users!"
|
||||
<textarea
|
||||
className={classes(Classes.inputDefault, "enter-comment", cl("input"))}
|
||||
onKeyDownCapture={e => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault(); // prevent newlines
|
||||
}
|
||||
onKeyDown={onKeyPress}
|
||||
onClick={() => {
|
||||
if (!token) {
|
||||
showToast("Opening authorization window...");
|
||||
authorize();
|
||||
}
|
||||
}}
|
||||
|
||||
style={{
|
||||
marginTop: "6px",
|
||||
resize: "none",
|
||||
marginBottom: "12px",
|
||||
overflow: "hidden",
|
||||
background: "transparent",
|
||||
border: "1px solid var(--profile-message-input-border-color)",
|
||||
fontSize: "14px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}}
|
||||
placeholder={
|
||||
!token
|
||||
? "You need to authorize to review users!"
|
||||
: isAuthor
|
||||
? `Update review for @${name}`
|
||||
: `Review @${name}`
|
||||
}
|
||||
onKeyDown={onKeyPress}
|
||||
onClick={() => {
|
||||
if (!token) {
|
||||
showToast("Opening authorization window...");
|
||||
authorize();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user