Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pages order info #2104

Merged
merged 14 commits into from
Nov 7, 2024
Merged
17 changes: 14 additions & 3 deletions backend/apps/ecommerce/resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,20 @@
def resolve_all_user_orders(self, info):
return Order.objects.all()

@staff_member_required
def resolve_all_shop_orders(self, info):
return Order.objects.filter(product__shop_item=True)
def resolve_paginated_shop_orders(self, info, limit, offset):
# Apply pagination if limit and offset are provided
orders = Order.objects.filter(product__shop_item=True).order_by(

Check warning on line 43 in backend/apps/ecommerce/resolvers.py

View check run for this annotation

Codecov / codecov/patch

backend/apps/ecommerce/resolvers.py#L43

Added line #L43 was not covered by tests
"delivered_product", "payment_status", "timestamp"
)
if offset is None:
offset = 0
orders = orders[offset:]

Check warning on line 48 in backend/apps/ecommerce/resolvers.py

View check run for this annotation

Codecov / codecov/patch

backend/apps/ecommerce/resolvers.py#L46-L48

Added lines #L46 - L48 were not covered by tests

if limit is None or limit > 300:

Check warning on line 50 in backend/apps/ecommerce/resolvers.py

View check run for this annotation

Codecov / codecov/patch

backend/apps/ecommerce/resolvers.py#L50

Added line #L50 was not covered by tests
# Add hard cap of maximum 300 orders per query. A bigger query would crash the website
limit = 300
orders = orders[:limit]
return orders

Check warning on line 54 in backend/apps/ecommerce/resolvers.py

View check run for this annotation

Codecov / codecov/patch

backend/apps/ecommerce/resolvers.py#L52-L54

Added lines #L52 - L54 were not covered by tests

@staff_member_required
def resolve_orders_by_status(self, info: "ResolveInfo", product_id, status):
Expand Down
2 changes: 1 addition & 1 deletion backend/apps/ecommerce/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class EcommerceQueries(graphene.ObjectType, EcommerceResolvers):
order = graphene.Field(OrderType, order_id=graphene.ID(required=True))
user_orders = graphene.List(NonNull(OrderType))
all_user_orders = graphene.List(NonNull(OrderType))
all_shop_orders = graphene.List(NonNull(OrderType))
paginated_shop_orders = graphene.List(graphene.NonNull(OrderType), limit=graphene.Int(), offset=graphene.Int())

orders_by_status = graphene.Field(
OrdersByStatusType, product_id=graphene.ID(required=True), status=graphene.String(required=True)
Expand Down
25 changes: 23 additions & 2 deletions backend/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,32 @@
}
},
{
"args": [],
"args": [
{
"defaultValue": null,
"description": null,
"name": "limit",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"defaultValue": null,
"description": null,
"name": "offset",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
}
],
"deprecationReason": null,
"description": null,
"isDeprecated": false,
"name": "allShopOrders",
"name": "paginatedShopOrders",
"type": {
"kind": "LIST",
"name": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { Swiper, SwiperSlide } from "swiper/react";
// Import Swiper styles
import "swiper/css";

import { Organization, OrganizationLink } from "./OrganizationLink";

import { Link } from "@/app/components/Link";

import { Organization, OrganizationLink } from "./OrganizationLink";

const organizations: Readonly<Organization[]> = [
{ name: "Janus Sosial", internalUrl: "/janus" },
{ name: "Bindeleddet", externalUrl: "https://www.bindeleddet.no" },
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/_components/LandingHero/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import { Box, Button, Container, Unstable_Grid2 as Grid, Typography } from "@mui/material";
import Image from "next/image";

import { OrganizationsSlider } from "./OrganizationsSlider";

import { Link } from "@/app/components/Link";
import Hero from "~/public/static/landing/hero.webp";

import { OrganizationsSlider } from "./OrganizationsSlider";

export const LandingHero: React.FC = () => {
return (
<>
Expand Down
93 changes: 66 additions & 27 deletions frontend/src/components/pages/organization/OrgShop.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,58 @@
import { useQuery } from "@apollo/client";
import { Box, Grid, Stack, Typography } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { useState } from "react";

import { AdminOrganizationFragment, AllShopOrdersDocument } from "@/generated/graphql";
import { AdminOrganizationFragment, PaginatedShopOrdersDocument } from "@/generated/graphql";

import { ShopSale } from "../orgs/ShopSale";
import { TableStepper } from "../orgs/TableStepper";

type Props = {
organization: AdminOrganizationFragment;
};
export const OrgProducts: React.FC<Props> = ({ organization }) => {
const { data, error } = useQuery(AllShopOrdersDocument);
const theme = useTheme();
const limit = 100;
const [page, setPage] = useState(0);

const handlePageChange = (newValue: number) => {
setPage(newValue);
};

const { data, error, loading } = useQuery(PaginatedShopOrdersDocument, {
variables: {
limit: limit + 1, // The number of orders you want to fetch
offset: page * limit, // The starting index (e.g., 0 for the first set of results)
},
});
if (error) return <p>Error</p>;

console.log(data);
if (organization.name !== "Janus linjeforening") {
if (organization.name.toLowerCase() !== "janus linjeforening") {
return (
<p>
Per nå har kun Janus tilgang på buttikk administrasjon. Etter hvert vil vi åpne for at flere kan bruke siden
</p>
);
}
if (data?.allShopOrders?.length === 0) {
if (data?.paginatedShopOrders!.length === 0) {
return <p>Ingen ordre</p>;
}
// Check if there is a next page (if we received less than `limit` items)
const hasNextPage = (data?.paginatedShopOrders && data.paginatedShopOrders.length < limit) ?? false;

return (
<>
<Stack direction={"row"} padding={2} border={3}>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<TableStepper page={page} hasNextPage={hasNextPage} handlePageChange={handlePageChange} />
<Stack
direction={"row"}
marginTop={"36px"}
spacing={0}
padding={1}
borderBottom={1}
sx={{ bgcolor: theme.palette.background.elevated, color: theme.palette.text.primary }}
>
<Box display="flex" alignItems="left" justifyContent="left" width={"25%"} padding={1}>
<Typography variant="body1">Navn på kunde</Typography>
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
Expand All @@ -36,33 +62,46 @@ export const OrgProducts: React.FC<Props> = ({ organization }) => {
<Typography variant="body1">Antall bestilt</Typography>
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<Typography variant="body1"> Betalt status</Typography>
<Typography variant="body1">Betalt status</Typography>
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"25%"} padding={1}>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
Mulige handlinger
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<Typography variant="body1"> Har vi levert varen</Typography>
<Typography variant="body1">Har vi levert varen</Typography>
</Box>
</Stack>
<Grid container spacing={0}>
{data?.allShopOrders?.map((order) => {
return (
<Grid key={order.id} item xs={12} sm={12} md={12}>
<Stack border={1}>
<ShopSale
name={order.user.firstName + " " + order.user.lastName}
product_name={order.product.name}
quantity={order.quantity}
has_paid={order.paymentStatus === "CAPTURED"}
is_delivered={order.deliveredProduct === true}
order_id={order.id}
/>
</Stack>

{loading ? (
<Typography padding={1}>Loading...</Typography>
) : (
data && (
<>
<Grid container spacing={0}>
{data?.paginatedShopOrders?.slice(0, limit).map((order) => {
return (
<Grid key={order.id} item xs={12} sm={12} md={12}>
<Stack borderBottom={1} borderColor={"gray"}>
<ShopSale
name={order.user.firstName + " " + order.user.lastName}
product_name={order.product.name}
quantity={order.quantity}
has_paid={order.paymentStatus === "CAPTURED"}
is_delivered={order.deliveredProduct === true}
order_id={order.id}
/>
</Stack>
</Grid>
);
})}
</Grid>
);
})}
</Grid>

<Stack marginTop={"18px"}>
<TableStepper page={page} hasNextPage={hasNextPage} handlePageChange={handlePageChange} />
</Stack>
</>
)
)}
</>
);
};
8 changes: 4 additions & 4 deletions frontend/src/components/pages/orgs/ShopSale.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export const ShopSale: React.FC<Props> = ({ name, product_name, quantity, has_pa
deliverProduct({ variables: { orderId: order_id } });
}
return (
<Stack direction={"row"} padding={2} spacing={1}>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<Stack direction={"row"} padding={1} spacing={0}>
<Box display="flex" alignItems="left" justifyContent="left" width={"25%"} padding={1}>
<Typography variant="body1">{name}</Typography>
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
Expand All @@ -36,7 +36,7 @@ export const ShopSale: React.FC<Props> = ({ name, product_name, quantity, has_pa
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<Typography variant="body1">Betalt: {has_paid ? "Ja" : "Nei"}</Typography>
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"25%"} padding={1}>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<Stack direction={"row"} spacing={1}>
<Tooltip title="Levert">
<Box display="inline" component="span">
Expand Down Expand Up @@ -69,7 +69,7 @@ export const ShopSale: React.FC<Props> = ({ name, product_name, quantity, has_pa
</Stack>
</Box>
<Box display="flex" alignItems="left" justifyContent="left" width={"15%"} padding={1}>
<Typography variant="body1">Varen er {delivered ? "levert" : "ikke levert"}</Typography>
<Typography variant="body1">{delivered ? "Levert" : "Ikke levert"}</Typography>
</Box>
</Stack>
);
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/components/pages/orgs/TableStepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { KeyboardArrowLeft, KeyboardArrowRight } from "@mui/icons-material";
import { Button, Typography, Stack } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import React from "react";

type Props = {
hasNextPage: boolean;
page: number;
handlePageChange: (page: number) => void;
};

export const TableStepper: React.FC<Props> = ({ hasNextPage, page, handlePageChange }) => {
const theme = useTheme();
const nextPage = () => handlePageChange(page + 1);
const prevPage = () => handlePageChange(page > 0 ? page - 1 : 0);

// Check if there is a next page (if we received less than `limit` items)
//const hasNextPage = (data?.paginatedShopOrders && data.paginatedShopOrders.length < limit) ?? false;

return (
<Stack
sx={{ maxWidth: 300, flexGrow: 1, position: "static", flexDirection: "row", justifyContent: "space-between" }}
>
<Button size="small" onClick={prevPage} disabled={page === 0}>
{theme.direction === "rtl" ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
Back
</Button>

<Typography>{page + 1}</Typography>

<Button size="small" onClick={nextPage} disabled={hasNextPage}>
Next
{theme.direction === "rtl" ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
</Button>
</Stack>
);
};
48 changes: 40 additions & 8 deletions frontend/src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,6 @@ export type Queries = {
allCategories?: Maybe<Array<CategoryType>>;
allEvents?: Maybe<Array<EventType>>;
allOrganizations?: Maybe<Array<OrganizationType>>;
allShopOrders?: Maybe<Array<OrderType>>;
allUserOrders?: Maybe<Array<OrderType>>;
allUsers?: Maybe<Array<UserType>>;
archiveByTypes: Array<ArchiveDocumentType>;
Expand All @@ -990,6 +989,7 @@ export type Queries = {
order?: Maybe<OrderType>;
ordersByStatus?: Maybe<OrdersByStatusType>;
organization?: Maybe<OrganizationType>;
paginatedShopOrders?: Maybe<Array<OrderType>>;
product?: Maybe<ProductType>;
products?: Maybe<Array<ProductType>>;
response?: Maybe<ResponseType>;
Expand Down Expand Up @@ -1090,6 +1090,11 @@ export type QueriesOrganizationArgs = {
slug?: InputMaybe<Scalars["String"]["input"]>;
};

export type QueriesPaginatedShopOrdersArgs = {
limit?: InputMaybe<Scalars["Int"]["input"]>;
offset?: InputMaybe<Scalars["Int"]["input"]>;
};

export type QueriesProductArgs = {
productId: Scalars["ID"]["input"];
};
Expand Down Expand Up @@ -1911,11 +1916,14 @@ export type AllUserOrdersQuery = {
}> | null;
};

export type AllShopOrdersQueryVariables = Exact<{ [key: string]: never }>;
export type PaginatedShopOrdersQueryVariables = Exact<{
limit?: InputMaybe<Scalars["Int"]["input"]>;
offset?: InputMaybe<Scalars["Int"]["input"]>;
}>;

export type AllShopOrdersQuery = {
export type PaginatedShopOrdersQuery = {
__typename?: "Queries";
allShopOrders?: Array<{
paginatedShopOrders?: Array<{
__typename?: "OrderType";
id: string;
quantity: number;
Expand Down Expand Up @@ -6643,19 +6651,43 @@ export const AllUserOrdersDocument = {
},
],
} as unknown as DocumentNode<AllUserOrdersQuery, AllUserOrdersQueryVariables>;
export const AllShopOrdersDocument = {
export const PaginatedShopOrdersDocument = {
kind: "Document",
definitions: [
{
kind: "OperationDefinition",
operation: "query",
name: { kind: "Name", value: "allShopOrders" },
name: { kind: "Name", value: "paginatedShopOrders" },
variableDefinitions: [
{
kind: "VariableDefinition",
variable: { kind: "Variable", name: { kind: "Name", value: "limit" } },
type: { kind: "NamedType", name: { kind: "Name", value: "Int" } },
},
{
kind: "VariableDefinition",
variable: { kind: "Variable", name: { kind: "Name", value: "offset" } },
type: { kind: "NamedType", name: { kind: "Name", value: "Int" } },
},
],
selectionSet: {
kind: "SelectionSet",
selections: [
{
kind: "Field",
name: { kind: "Name", value: "allShopOrders" },
name: { kind: "Name", value: "paginatedShopOrders" },
arguments: [
{
kind: "Argument",
name: { kind: "Name", value: "limit" },
value: { kind: "Variable", name: { kind: "Name", value: "limit" } },
},
{
kind: "Argument",
name: { kind: "Name", value: "offset" },
value: { kind: "Variable", name: { kind: "Name", value: "offset" } },
},
],
selectionSet: {
kind: "SelectionSet",
selections: [{ kind: "FragmentSpread", name: { kind: "Name", value: "Order" } }],
Expand Down Expand Up @@ -6718,7 +6750,7 @@ export const AllShopOrdersDocument = {
},
},
],
} as unknown as DocumentNode<AllShopOrdersQuery, AllShopOrdersQueryVariables>;
} as unknown as DocumentNode<PaginatedShopOrdersQuery, PaginatedShopOrdersQueryVariables>;
export const CreateEventDocument = {
kind: "Document",
definitions: [
Expand Down
Loading
Loading