@alphabite/medusa-reviews
Version:
Alphabite's Medusa Reviews Plugin
175 lines (174 loc) • 5.04 kB
JavaScript
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
};