From 350d31d8d8b61950783992dc3688bb9e13690092 Mon Sep 17 00:00:00 2001 From: Nikolai R Kristiansen Date: Sat, 30 Oct 2021 18:21:16 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Dont=20show=20inactive=20users=20in?= =?UTF-8?q?=20register=20view?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/package-lock.json | 34 +++++-- frontend/package.json | 1 + frontend/src/features/Register.tsx | 22 ++-- frontend/src/features/allUsers.graphql | 13 +++ frontend/src/features/useRegister.ts | 23 +++++ frontend/src/types.ts | 134 ++++++++++++++++++------- main/api/schema.py | 18 +--- main/api/types.py | 44 ++++++++ 8 files changed, 221 insertions(+), 68 deletions(-) create mode 100644 frontend/src/features/allUsers.graphql create mode 100644 frontend/src/features/useRegister.ts create mode 100644 main/api/types.py diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 12c19a8..e86be56 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "@apollo/client": "^3.4.16", + "date-fns": "^2.25.0", "graphql": "^15.7.2", "react": "^17.0.2", "react-dom": "^17.0.2" @@ -4123,10 +4124,16 @@ "dev": true }, "node_modules/date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", + "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } }, "node_modules/debounce": { "version": "1.2.1", @@ -8041,6 +8048,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "node_modules/listr-verbose-renderer/node_modules/date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, "node_modules/listr-verbose-renderer/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -14637,10 +14650,9 @@ "dev": true }, "date-fns": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", - "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", - "dev": true + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", + "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==" }, "debounce": { "version": "1.2.1", @@ -17578,6 +17590,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index faed41a..b446c35 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ }, "dependencies": { "@apollo/client": "^3.4.16", + "date-fns": "^2.25.0", "graphql": "^15.7.2", "react": "^17.0.2", "react-dom": "^17.0.2" diff --git a/frontend/src/features/Register.tsx b/frontend/src/features/Register.tsx index c0e7f77..c1d6ae6 100644 --- a/frontend/src/features/Register.tsx +++ b/frontend/src/features/Register.tsx @@ -1,21 +1,25 @@ import React from "react"; -import { Product, useAllProductsQuery } from "../types"; +import { Product, User } from "../types"; +import { useRegister } from "./useRegister"; export const Register: React.FC = () => { - const { data, error, loading } = useAllProductsQuery({ variables: { active: true } }); - if (error) { - console.log("🔥", error); - return null; - } + const { users, products, loading, showAll, setShowAll } = useRegister(); if (loading) { return
...
; } return (
- {data?.allProducts.map((product: Product) => { - return
{product.name}
; - })}{" "} +
+ {users.map((user: User) => { + return
{user.firstName}
; + })} +
+
+ {products.map((product: Product) => { + return
{product.name}
; + })} +
); }; diff --git a/frontend/src/features/allUsers.graphql b/frontend/src/features/allUsers.graphql new file mode 100644 index 0000000..1715fd5 --- /dev/null +++ b/frontend/src/features/allUsers.graphql @@ -0,0 +1,13 @@ +query allUsers { + allUsers { + id + firstName + lastName + profile { + id + balance + image + lastPurchaseDate + } + } +} diff --git a/frontend/src/features/useRegister.ts b/frontend/src/features/useRegister.ts new file mode 100644 index 0000000..cb9dcd0 --- /dev/null +++ b/frontend/src/features/useRegister.ts @@ -0,0 +1,23 @@ +import { parseISO, subDays } from "date-fns"; +import { useState } from "react"; + +import { useAllProductsQuery, useAllUsersQuery, User } from "../types"; + +const activeLimitDays = 365 / 2; + +export const useRegister = () => { + const [showAll, setShowAll] = useState(false); + const { data, loading } = useAllProductsQuery({ variables: { active: true } }); + const { data: usersData, loading: usersLoading } = useAllUsersQuery(); + + const allUsers = usersData?.allUsers || []; + const users = showAll + ? allUsers + : allUsers.filter((user: User) => { + const balance = user.profile?.balance || 0; + const active = parseISO(user.profile?.lastPurchaseDate) >= subDays(new Date(), activeLimitDays); + return balance >= 15 && active; + }); + + return { loading: loading || usersLoading, users, products: data?.allProducts || [], showAll, setShowAll }; +}; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index a505d3d..0f91c39 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -1,10 +1,10 @@ -import { gql } from "@apollo/client"; -import * as Apollo from "@apollo/client"; +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; export type Maybe = T | null; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; -const defaultOptions = {}; +const defaultOptions = {} /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { ID: string; @@ -12,49 +12,73 @@ export type Scalars = { Boolean: boolean; Int: number; Float: number; + /** Date with time (isoformat) */ + DateTime: any; }; export type Product = { - __typename?: "Product"; - id: Scalars["ID"]; - name: Scalars["String"]; - salePriceExt: Scalars["Float"]; - salePriceInt: Scalars["Float"]; + __typename?: 'Product'; + id: Scalars['ID']; + name: Scalars['String']; + salePriceExt: Scalars['Float']; + salePriceInt: Scalars['Float']; }; export type ProductFilter = { - active?: Maybe; - id?: Maybe; + active?: Maybe; + id?: Maybe; }; export type Query = { - __typename?: "Query"; + __typename?: 'Query'; allProducts: Array; + allUsers: Array; }; + export type QueryAllProductsArgs = { filters?: Maybe; }; -export type AllProductsQueryVariables = Exact<{ - active: Scalars["Boolean"]; -}>; - -export type AllProductsQuery = { - __typename?: "Query"; - allProducts: Array<{ __typename?: "Product"; id: string; name: string; salePriceExt: number; salePriceInt: number }>; +export type User = { + __typename?: 'User'; + firstName: Scalars['String']; + id: Scalars['ID']; + lastName: Scalars['String']; + profile?: Maybe; }; +export type UserProfile = { + __typename?: 'UserProfile'; + balance: Scalars['Float']; + id: Scalars['ID']; + image: Scalars['String']; + lastPurchaseDate: Scalars['DateTime']; +}; + +export type AllProductsQueryVariables = Exact<{ + active: Scalars['Boolean']; +}>; + + +export type AllProductsQuery = { __typename?: 'Query', allProducts: Array<{ __typename?: 'Product', id: string, name: string, salePriceExt: number, salePriceInt: number }> }; + +export type AllUsersQueryVariables = Exact<{ [key: string]: never; }>; + + +export type AllUsersQuery = { __typename?: 'Query', allUsers: Array<{ __typename?: 'User', id: string, firstName: string, lastName: string, profile?: { __typename?: 'UserProfile', id: string, balance: number, image: string, lastPurchaseDate: any } | null | undefined }> }; + + export const AllProductsDocument = gql` - query allProducts($active: Boolean!) { - allProducts(filters: { active: $active }) { - id - name - salePriceExt - salePriceInt - } + query allProducts($active: Boolean!) { + allProducts(filters: {active: $active}) { + id + name + salePriceExt + salePriceInt } -`; +} + `; /** * __useAllProductsQuery__ @@ -73,15 +97,55 @@ export const AllProductsDocument = gql` * }); */ export function useAllProductsQuery(baseOptions: Apollo.QueryHookOptions) { - const options = { ...defaultOptions, ...baseOptions }; - return Apollo.useQuery(AllProductsDocument, options); -} -export function useAllProductsLazyQuery( - baseOptions?: Apollo.LazyQueryHookOptions -) { - const options = { ...defaultOptions, ...baseOptions }; - return Apollo.useLazyQuery(AllProductsDocument, options); -} + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(AllProductsDocument, options); + } +export function useAllProductsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(AllProductsDocument, options); + } export type AllProductsQueryHookResult = ReturnType; export type AllProductsLazyQueryHookResult = ReturnType; export type AllProductsQueryResult = Apollo.QueryResult; +export const AllUsersDocument = gql` + query allUsers { + allUsers { + id + firstName + lastName + profile { + id + balance + image + lastPurchaseDate + } + } +} + `; + +/** + * __useAllUsersQuery__ + * + * To run a query within a React component, call `useAllUsersQuery` and pass it any options that fit your needs. + * When your component renders, `useAllUsersQuery` 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 } = useAllUsersQuery({ + * variables: { + * }, + * }); + */ +export function useAllUsersQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(AllUsersDocument, options); + } +export function useAllUsersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(AllUsersDocument, options); + } +export type AllUsersQueryHookResult = ReturnType; +export type AllUsersLazyQueryHookResult = ReturnType; +export type AllUsersQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/main/api/schema.py b/main/api/schema.py index 355ef2e..f6daf93 100644 --- a/main/api/schema.py +++ b/main/api/schema.py @@ -1,27 +1,13 @@ import strawberry import strawberry_django -from strawberry_django import auto -from main import models - - -@strawberry_django.filters.filter(models.Product) -class ProductFilter: - id: auto - active: auto - - -@strawberry_django.type(models.Product, filters=ProductFilter) -class Product: - id: auto - name: auto - sale_price_int: auto - sale_price_ext: auto +from main.api.types import Product, User @strawberry.type class Query: all_products: list[Product] = strawberry_django.field() + all_users: list[User] = strawberry_django.field() schema = strawberry.Schema(query=Query) diff --git a/main/api/types.py b/main/api/types.py new file mode 100644 index 0000000..ed5ae86 --- /dev/null +++ b/main/api/types.py @@ -0,0 +1,44 @@ +from datetime import datetime + +import strawberry +import strawberry_django +from django.contrib.auth import get_user_model +from strawberry_django import auto + +from main import models + +UserModel = get_user_model() + + +@strawberry_django.filters.filter(models.Product) +class ProductFilter: + id: auto + active: auto + + +@strawberry_django.type(models.Product, filters=ProductFilter) +class Product: + id: auto + name: auto + sale_price_int: auto + sale_price_ext: auto + + +@strawberry_django.type(models.UserProfile) +class UserProfile: + id: auto + balance: auto + image: auto + + @strawberry.field() + def last_purchase_date(self) -> datetime: + return self.last_purchase_date() + + +@strawberry_django.type(UserModel) +class User: + id: auto + first_name: auto + last_name: auto + profile: UserProfile + # todo