UNPKG

@alphabite/medusa-reviews

Version:

Alphabite's Medusa Reviews Plugin

175 lines (174 loc) 5.04 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { defineRouteConfig } from "@medusajs/admin-sdk"; import { ChatBubbleLeftRight } from "@medusajs/icons"; import { createDataTableColumnHelper, StatusBadge, createDataTableCommandHelper, useDataTable, Container, DataTable, Heading, Toaster, toast } from "@medusajs/ui"; import { useQuery } from "@tanstack/react-query"; import { useState, useMemo } from "react"; import Medusa from "@medusajs/js-sdk"; import { Link } from "react-router-dom"; const sdk = new Medusa({ baseUrl: "http://localhost:9000", debug: process.env.NODE_ENV === "development", auth: { type: "session" } }); const columnHelper = createDataTableColumnHelper(); const columns = [ columnHelper.select(), columnHelper.accessor("id", { header: "ID" }), columnHelper.accessor("title", { header: "Title" }), columnHelper.accessor("rating", { header: "Rating" }), columnHelper.accessor("content", { header: "Content" }), columnHelper.accessor("status", { header: "Status", cell: ({ row }) => { const color = row.original.status === "approved" ? "green" : row.original.status === "rejected" ? "red" : "grey"; return /* @__PURE__ */ jsx(StatusBadge, { color, children: row.original.status.charAt(0).toUpperCase() + row.original.status.slice(1) }); } }), columnHelper.accessor("product", { header: "Product", cell: ({ row }) => { var _a; return /* @__PURE__ */ jsx(Link, { to: `/products/${row.original.product_id}`, children: (_a = row.original.product) == null ? void 0 : _a.title }); } }) ]; const commandHelper = createDataTableCommandHelper(); const useCommands = (refetch) => { return [ commandHelper.command({ label: "Approve", shortcut: "A", action: async (selection) => { const reviewsToApproveIds = Object.keys(selection); sdk.client.fetch("/admin/reviews/status", { method: "POST", body: { ids: reviewsToApproveIds, status: "approved" } }).then(() => { toast.success("Reviews approved"); refetch(); }).catch(() => { toast.error("Failed to approve reviews"); }); } }), commandHelper.command({ label: "Reject", shortcut: "R", action: async (selection) => { const reviewsToRejectIds = Object.keys(selection); sdk.client.fetch("/admin/reviews/status", { method: "POST", body: { ids: reviewsToRejectIds, status: "rejected" } }).then(() => { toast.success("Reviews rejected"); refetch(); }).catch(() => { toast.error("Failed to reject reviews"); }); } }) ]; }; const limit = 15; const ReviewsPage = () => { const [rowSelection, setRowSelection] = useState( {} ); const [pagination, setPagination] = useState({ pageSize: limit, pageIndex: 0 }); const offset = useMemo(() => { return pagination.pageIndex * limit; }, [pagination]); const { data, isLoading, refetch } = useQuery({ queryKey: ["reviews", offset, limit], queryFn: () => sdk.client.fetch("/admin/reviews", { query: { offset: pagination.pageIndex * pagination.pageSize, limit: pagination.pageSize, order: "-created_at" } }) }); const commands = useCommands(refetch); const table = useDataTable({ commands, rowSelection: { state: rowSelection, onRowSelectionChange: setRowSelection }, columns, data: (data == null ? void 0 : data.reviews) || [], rowCount: (data == null ? void 0 : data.count) || 0, isLoading, pagination: { state: pagination, onPaginationChange: setPagination }, getRowId: (row) => row.id }); return /* @__PURE__ */ jsxs(Container, { children: [ /* @__PURE__ */ jsxs(DataTable, { instance: table, children: [ /* @__PURE__ */ jsx(DataTable.CommandBar, { selectedLabel: (count) => `${count} selected` }), /* @__PURE__ */ jsx(DataTable.Toolbar, { className: "flex flex-col items-start justify-between gap-2 md:flex-row md:items-center", children: /* @__PURE__ */ jsx(Heading, { children: "Reviews" }) }), /* @__PURE__ */ jsx(DataTable.Table, {}), /* @__PURE__ */ jsx(DataTable.Pagination, {}) ] }), /* @__PURE__ */ jsx(Toaster, {}) ] }); }; const config = defineRouteConfig({ label: "Reviews", icon: ChatBubbleLeftRight }); const widgetModule = { widgets: [] }; const routeModule = { routes: [ { Component: ReviewsPage, path: "/reviews" } ] }; const menuItemModule = { menuItems: [ { label: config.label, icon: config.icon, path: "/reviews", nested: void 0 } ] }; const formModule = { customFields: {} }; const displayModule = { displays: {} }; const plugin = { widgetModule, routeModule, menuItemModule, formModule, displayModule }; export { plugin as default };