Skip to content

Commit

Permalink
feat(admin): ✨ category admin panel init
Browse files Browse the repository at this point in the history
  • Loading branch information
sahrohit committed Sep 22, 2023
1 parent 7bc94fc commit 128242b
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 28 deletions.
9 changes: 6 additions & 3 deletions apps/admin/next.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
reactStrictMode: true,
images: {
domains: ["images.unsplash.com"],
},
};

module.exports = nextConfig
module.exports = nextConfig;
26 changes: 13 additions & 13 deletions apps/admin/src/config/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FaUser } from "react-icons/fa";
import { BiPackage, BiHomeAlt, BiSupport } from "react-icons/bi";
import { BiPackage, BiSupport, BiCategoryAlt } from "react-icons/bi";
import { TbTruckReturn } from "react-icons/tb";
import { AiOutlineSetting } from "react-icons/ai";
import { BsArrowReturnLeft } from "react-icons/bs";
Expand All @@ -16,27 +16,27 @@ export const ORDER_NAV_LINKS = [
icon: TbTruckReturn,
},
{
label: "Address",
href: "/dashboard/address",
icon: BiHomeAlt,
label: "Category",
href: "/dashboard/category",
icon: BiCategoryAlt,
},
];

export const ACCOUNT_NAV_LINKS = [
{
label: "Account",
href: "/dashboard",
icon: FaUser,
},
{
label: "Preference",
href: "/dashboard/preference",
// {
// label: "Account",
// href: "/dashboard",
// icon: FaUser,
// },
{
label: "Store Settings",
href: "/dashboard/settings",
icon: AiOutlineSetting,
},
{
label: "Manage Staffs",
href: "/dashboard/staffs",
icon: AiOutlineSetting,
icon: FaUser,
},
];

Expand Down
83 changes: 83 additions & 0 deletions apps/admin/src/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ export type ProductCategory = {
imageURL: Scalars["String"];
name: Scalars["String"];
products?: Maybe<Array<Product>>;
tenant: Tenant;
tenantId: Scalars["Int"];
updated_at: Scalars["String"];
};

Expand All @@ -536,6 +538,8 @@ export type ProductCategoryWithProductCount = {
name: Scalars["String"];
product_count: Scalars["Int"];
products?: Maybe<Array<Product>>;
tenant: Tenant;
tenantId: Scalars["Int"];
updated_at: Scalars["String"];
};

Expand Down Expand Up @@ -1288,6 +1292,23 @@ export type VerifyEmailMutation = {
verifyEmail: boolean;
};

export type CategoriesQueryVariables = Exact<{ [key: string]: never }>;

export type CategoriesQuery = {
__typename?: "Query";
categories: Array<{
__typename?: "ProductCategory";
id: number;
name: string;
identifier: string;
desc: string;
imageURL: string;
tenantId: number;
created_at: string;
updated_at: string;
}>;
};

export type MeStaffQueryVariables = Exact<{ [key: string]: never }>;

export type MeStaffQuery = {
Expand Down Expand Up @@ -2213,6 +2234,68 @@ export type VerifyEmailMutationOptions = Apollo.BaseMutationOptions<
VerifyEmailMutation,
VerifyEmailMutationVariables
>;
export const CategoriesDocument = gql`
query Categories {
categories {
id
name
identifier
desc
imageURL
tenantId
created_at
updated_at
}
}
`;

/**
* __useCategoriesQuery__
*
* To run a query within a React component, call `useCategoriesQuery` and pass it any options that fit your needs.
* When your component renders, `useCategoriesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useCategoriesQuery({
* variables: {
* },
* });
*/
export function useCategoriesQuery(
baseOptions?: Apollo.QueryHookOptions<
CategoriesQuery,
CategoriesQueryVariables
>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useQuery<CategoriesQuery, CategoriesQueryVariables>(
CategoriesDocument,
options
);
}
export function useCategoriesLazyQuery(
baseOptions?: Apollo.LazyQueryHookOptions<
CategoriesQuery,
CategoriesQueryVariables
>
) {
const options = { ...defaultOptions, ...baseOptions };
return Apollo.useLazyQuery<CategoriesQuery, CategoriesQueryVariables>(
CategoriesDocument,
options
);
}
export type CategoriesQueryHookResult = ReturnType<typeof useCategoriesQuery>;
export type CategoriesLazyQueryHookResult = ReturnType<
typeof useCategoriesLazyQuery
>;
export type CategoriesQueryResult = Apollo.QueryResult<
CategoriesQuery,
CategoriesQueryVariables
>;
export const MeStaffDocument = gql`
query MeStaff {
meStaff {
Expand Down
12 changes: 12 additions & 0 deletions apps/admin/src/graphql/query/category/categories.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
query Categories {
categories {
id
name
identifier
desc
imageURL
tenantId
created_at
updated_at
}
}
192 changes: 192 additions & 0 deletions apps/admin/src/pages/dashboard/category.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/* eslint-disable no-nested-ternary */
import {
Flex,
FormControl,
FormLabel,
HStack,
Input,
InputGroup,
InputLeftElement,
Select,
Spinner,
Stack,
Text,
VStack,
} from "@chakra-ui/react";
import { BsSearch } from "react-icons/bs";
import { CellContext, createColumnHelper } from "@tanstack/react-table";
import Image from "next/image";
import Result from "@/components/shared/Result";
import HeadingGroup from "@/components/ui/HeadingGroup";
import { DataTable } from "@/components/ui/table";
import { type ProductCategory, useCategoriesQuery } from "@/generated/graphql";
import ConfirmationModal from "@/components/helpers/ConfirmationModal";
import ModalButton from "@/components/ui/ModalButton";

export const TableActions = () => (
<Stack
w="full"
spacing="4"
direction={{ base: "column", md: "row" }}
justify="space-between"
position="sticky"
top="0"
>
<HStack>
<FormControl minW={{ md: "320px" }} id="search">
<InputGroup size="sm">
<FormLabel srOnly>Filter by name or email</FormLabel>
<InputLeftElement pointerEvents="none" color="gray.400">
<BsSearch />
</InputLeftElement>
<Input
// value={searchText}
// onChange={(e) => setSearchText(e.target.value)}
rounded="base"
type="search"
placeholder="Filter by name or email..."
/>
</InputGroup>
</FormControl>
<Select
w={{ base: "300px", md: "full" }}
rounded="base"
size="sm"
// value={selectedRole}
// onChange={(e) => setSelectedRole(Number(e.target.value))}
>
<option value={0}>All categories</option>
{/* {categoriesData?.categories
.filter((r) => r.id !== 1)
.map((role) => (
<option key={`role-${role.id}`} value={role.id}>
{role.name}
</option>
))} */}
</Select>
</HStack>
</Stack>
);

const columnHelper = createColumnHelper<ProductCategory>();

const columns = [
// columnHelper.accessor("name", {
// cell: (info) => <Checkbox size="lg" />,
// header: "",
// }),
columnHelper.accessor("name", {
cell: (info) => (
<HStack spacing="4" px="2" w="full">
<Image
alt={info.getValue()}
height={48}
width={48}
src={info.row.original.imageURL}
style={{
borderRadius: "4px",
}}
/>
<Flex direction="column">
<Text fontWeight="medium">{info.getValue()} </Text>
</Flex>
</HStack>
),
header: "Name",
}),
columnHelper.accessor("desc", {
cell: (info) => info.getValue(),
header: "Desc",
}),
// columnHelper.accessor("user", {
// cell: (info) => (
// <UserProfile
// email={info.getValue()?.email ?? ""}
// imageUrl={info.getValue()?.imageUrl ?? ""}
// name={`${info.getValue()?.first_name} ${info.getValue()?.last_name}`}
// />
// ),
// header: "User",
// }),
// columnHelper.accessor("user.role", {
// cell: (info) => <RoleSelector info={info} />,
// header: "Role",
// }),
// columnHelper.accessor("status", {
// cell: (info) => (
// <Badge fontSize="xs" colorScheme={colorFromStatus(info.getValue())}>
// {info.getValue()}
// </Badge>
// ),
// header: "Status",
// }),
columnHelper.accessor("id", {
cell: (info) => <CategoryActions info={info} />,
header: "Actions",
}),
];

const CategoryActions = ({
info,
}: {
info: CellContext<ProductCategory, number>;
}) => (
<HStack gap={2}>
<ModalButton
modalHeader={`Edit ${info.row.original.name}`}
size="sm"
colorScheme="primary"
buttonText="Edit"
>
Editing
</ModalButton>
<ConfirmationModal
bodyText={`Are you sure you want to delete category ${info.row.original.name}?`}
confirmButtonProps={{ colorScheme: "red" }}
headerText={`Delete Category ${info.row.original.name}?`}
onSuccess={() => {
console.log("Deleted");
}}
size="sm"
confirmText="delete"
colorScheme="red"
>
Delete
</ConfirmationModal>
</HStack>
);

const SettingsPage = () => {
const { data, loading, error } = useCategoriesQuery();

if (error) {
return (
<Result
heading={error.name}
text={error.message}
type="error"
dump={error.stack}
/>
);
}

return (
<VStack gap={4} w="full">
<HeadingGroup
title="Manage Staffs"
description="Manage your staffs here."
/>
<TableActions />
{loading ? (
<Spinner />
) : (
<DataTable
columns={columns}
data={data?.categories as ProductCategory[]}
/>
)}
</VStack>
);
};

export default SettingsPage;
3 changes: 3 additions & 0 deletions apps/admin/src/pages/dashboard/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const CategoryPage = () => <div>CategoryPage</div>;

export default CategoryPage;
Loading

2 comments on commit 128242b

@vercel
Copy link

@vercel vercel bot commented on 128242b Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ecommerce-admin-client – ./apps/admin

ecommerce-admin-client-git-main-sahrohit.vercel.app
adminpasal.vercel.app
ecommerce-admin-client-sahrohit.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 128242b Sep 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.