From 23f448ecd97872568ed926be0cf5b80b7fb6cab0 Mon Sep 17 00:00:00 2001 From: Divya Pahuja Date: Sun, 15 Mar 2026 16:19:55 +0530 Subject: [PATCH] feat: redesign admin dashboard using polaris layouts and extracted custom components --- app/components/DashboardMetrics.jsx | 34 +++++++++++++ app/components/ReviewList.jsx | 68 ++++++++++++++++++++++++++ app/components/StorefrontSetupCard.jsx | 20 ++++++++ app/components/TechStackCard.jsx | 23 +++++++++ app/routes/app._index.jsx | 63 ++++++++++-------------- 5 files changed, 172 insertions(+), 36 deletions(-) create mode 100644 app/components/DashboardMetrics.jsx create mode 100644 app/components/ReviewList.jsx create mode 100644 app/components/StorefrontSetupCard.jsx create mode 100644 app/components/TechStackCard.jsx diff --git a/app/components/DashboardMetrics.jsx b/app/components/DashboardMetrics.jsx new file mode 100644 index 0000000..92b9869 --- /dev/null +++ b/app/components/DashboardMetrics.jsx @@ -0,0 +1,34 @@ +import { Card, BlockStack, Text, InlineGrid, Box } from "@shopify/polaris"; + +export function DashboardMetrics({ reviews }) { + const totalReviews = reviews.length; + + // Calculate unique products + const uniqueProducts = new Set(reviews.map(r => r.product_id).filter(Boolean)).size; + + return ( + + + + + Total Reviews + + + {totalReviews} + + + + + + + + Products Reviewed + + + {uniqueProducts} + + + + + ); +} diff --git a/app/components/ReviewList.jsx b/app/components/ReviewList.jsx new file mode 100644 index 0000000..e457e72 --- /dev/null +++ b/app/components/ReviewList.jsx @@ -0,0 +1,68 @@ +import { + EmptyState, + ResourceList, + ResourceItem, + InlineStack, + Avatar, + BlockStack, + Text, + Badge +} from "@shopify/polaris"; + +export function ReviewList({ reviews }) { + if (reviews.length === 0) { + return ( + +

Track your customer feedback in one place. Your store has no reviews yet.

+
+ ); + } + + return ( + { + const { id, customer_name, content, rating, product_id } = item; + const productIdNum = product_id?.split('/').pop() || ''; + + return ( + { + window.open(`shopify:admin/products/${productIdNum}`, "_top"); + }} + accessibilityLabel={`View details for ${customer_name}`} + > + + + + + + {customer_name || 'Anonymous'} + + + {content} + + + + + + + {rating || "5"} / 5 ★ + + + Product ID: {productIdNum} + + + + + ); + }} + /> + ); +} diff --git a/app/components/StorefrontSetupCard.jsx b/app/components/StorefrontSetupCard.jsx new file mode 100644 index 0000000..310b9ab --- /dev/null +++ b/app/components/StorefrontSetupCard.jsx @@ -0,0 +1,20 @@ +import { Card, BlockStack, Text, Button } from "@shopify/polaris"; +import { ExternalIcon } from "@shopify/polaris-icons"; + +export function StorefrontSetupCard() { + return ( + + + + Storefront Setup + + + Ensure the "Reviews" block is added to your Default Product Template in the Online Store editor. + + + + + ); +} diff --git a/app/components/TechStackCard.jsx b/app/components/TechStackCard.jsx new file mode 100644 index 0000000..5d5c541 --- /dev/null +++ b/app/components/TechStackCard.jsx @@ -0,0 +1,23 @@ +import { Card, BlockStack, Text, Box, List } from "@shopify/polaris"; + +export function TechStackCard() { + return ( + + + + Tech Stack + + + + This app is running 100% database-less, powered only by Shopify. + + + + Storage: Shopify Metaobjects + Auth: App Proxy & Admin API + Design: Shopify Polaris + + + + ); +} diff --git a/app/routes/app._index.jsx b/app/routes/app._index.jsx index acd7462..9cf3642 100644 --- a/app/routes/app._index.jsx +++ b/app/routes/app._index.jsx @@ -1,13 +1,19 @@ import { authenticate } from "../shopify.server"; import { useLoaderData } from "react-router"; +import { Page, Layout, Card, BlockStack } from "@shopify/polaris"; + +import { DashboardMetrics } from "../components/DashboardMetrics"; +import { ReviewList } from "../components/ReviewList"; +import { TechStackCard } from "../components/TechStackCard"; +import { StorefrontSetupCard } from "../components/StorefrontSetupCard"; export const loader = async ({ request }) => { - const { admin, session } = await authenticate.admin(request); + const { admin } = await authenticate.admin(request); // Fetch some reviews to show in the admin dashboard const response = await admin.graphql(`#graphql query { - metaobjects(first: 10, type: "custom_product_review") { + metaobjects(first: 50, type: "custom_product_review") { edges { node { id @@ -31,39 +37,24 @@ export default function Index() { const { reviews } = useLoaderData(); return ( - - - - All reviews are stored directly in Shopify Metaobjects. You can view, edit, or delete them here. - - - {reviews.length === 0 ? ( - No reviews found yet. Try adding one from your store! - ) : ( - - {reviews.map((r) => ( - - - {r.customer_name || 'Anonymous'} - {r.content} - Product ID: {r.product_id} - - - ))} - - )} - - - - - This app is 100% database-less. - - - Storage: Shopify Metaobjects - Auth: App Proxy & Admin API - Framework: React Router - - - + + + + + + + + + + + + + + + + + + + ); }