diff options
Diffstat (limited to 'stepped-solutions/53')
| -rwxr-xr-x | stepped-solutions/53/backend/datamodel.graphql | 57 | ||||
| -rwxr-xr-x | stepped-solutions/53/backend/src/generated/prisma.graphql | 1855 | ||||
| -rwxr-xr-x | stepped-solutions/53/backend/src/resolvers/Query.js | 55 | ||||
| -rwxr-xr-x | stepped-solutions/53/backend/src/schema.graphql | 37 | ||||
| -rwxr-xr-x | stepped-solutions/53/frontend/components/Cart.js | 66 | ||||
| -rwxr-xr-x | stepped-solutions/53/frontend/components/Order.js | 91 | ||||
| -rwxr-xr-x | stepped-solutions/53/frontend/components/Search.js | 94 | ||||
| -rwxr-xr-x | stepped-solutions/53/frontend/components/TakeMyMoney.js | 77 | ||||
| -rwxr-xr-x | stepped-solutions/53/frontend/components/styles/OrderStyles.js | 37 | ||||
| -rwxr-xr-x | stepped-solutions/53/frontend/pages/order.js | 12 |
10 files changed, 2381 insertions, 0 deletions
diff --git a/stepped-solutions/53/backend/datamodel.graphql b/stepped-solutions/53/backend/datamodel.graphql new file mode 100755 index 0000000..ce9ae38 --- /dev/null +++ b/stepped-solutions/53/backend/datamodel.graphql @@ -0,0 +1,57 @@ +enum Permission { + ADMIN + USER + ITEMCREATE + ITEMUPDATE + ITEMDELETE + PERMISSIONUPDATE +} + +type User { + id: ID! @unique + name: String! + email: String! @unique + password: String! + resetToken: String + resetTokenExpiry: String + permissions: [Permission] + cart: [CartItem!]! +} + +type Item { + id: ID! @unique + title: String! + description: String! + image: String + largeImage: String + price: Int! + user: User! +} + +type CartItem { + id: ID! @unique + quantity: Int! @default(value: 1) + item: Item # relationship to Item + user: User! # relationship to User +} + +type OrderItem { + id: ID! @unique + title: String! + description: String! + image: String! + largeImage: String! + price: Int! + quantity: Int! @default(value: 1) + user: User +} + +type Order { + id: ID! @unique + items: [OrderItem!]! + total: Int! + user: User! + charge: String! + createdAt: DateTime! + updatedAt: DateTime! +} diff --git a/stepped-solutions/53/backend/src/generated/prisma.graphql b/stepped-solutions/53/backend/src/generated/prisma.graphql new file mode 100755 index 0000000..067c87e --- /dev/null +++ b/stepped-solutions/53/backend/src/generated/prisma.graphql @@ -0,0 +1,1855 @@ +# source: https://us1.prisma.sh/wesbos/siccccccccck-fits/dev +# timestamp: Fri Aug 24 2018 14:33:54 GMT-0400 (EDT) + +type AggregateCartItem { + count: Int! +} + +type AggregateItem { + count: Int! +} + +type AggregateOrder { + count: Int! +} + +type AggregateOrderItem { + count: Int! +} + +type AggregateUser { + count: Int! +} + +type BatchPayload { + """The number of nodes that have been affected by the Batch operation.""" + count: Long! +} + +type CartItem implements Node { + id: ID! + quantity: Int! + item(where: ItemWhereInput): Item + user(where: UserWhereInput): User! +} + +"""A connection to a list of items.""" +type CartItemConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [CartItemEdge]! + aggregate: AggregateCartItem! +} + +input CartItemCreateInput { + quantity: Int + item: ItemCreateOneInput + user: UserCreateOneWithoutCartInput! +} + +input CartItemCreateManyWithoutUserInput { + create: [CartItemCreateWithoutUserInput!] + connect: [CartItemWhereUniqueInput!] +} + +input CartItemCreateWithoutUserInput { + quantity: Int + item: ItemCreateOneInput +} + +"""An edge in a connection.""" +type CartItemEdge { + """The item at the end of the edge.""" + node: CartItem! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum CartItemOrderByInput { + id_ASC + id_DESC + quantity_ASC + quantity_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type CartItemPreviousValues { + id: ID! + quantity: Int! +} + +type CartItemSubscriptionPayload { + mutation: MutationType! + node: CartItem + updatedFields: [String!] + previousValues: CartItemPreviousValues +} + +input CartItemSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [CartItemSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [CartItemSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [CartItemSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: CartItemWhereInput +} + +input CartItemUpdateInput { + quantity: Int + item: ItemUpdateOneInput + user: UserUpdateOneWithoutCartInput +} + +input CartItemUpdateManyWithoutUserInput { + create: [CartItemCreateWithoutUserInput!] + connect: [CartItemWhereUniqueInput!] + disconnect: [CartItemWhereUniqueInput!] + delete: [CartItemWhereUniqueInput!] + update: [CartItemUpdateWithWhereUniqueWithoutUserInput!] + upsert: [CartItemUpsertWithWhereUniqueWithoutUserInput!] +} + +input CartItemUpdateWithoutUserDataInput { + quantity: Int + item: ItemUpdateOneInput +} + +input CartItemUpdateWithWhereUniqueWithoutUserInput { + where: CartItemWhereUniqueInput! + data: CartItemUpdateWithoutUserDataInput! +} + +input CartItemUpsertWithWhereUniqueWithoutUserInput { + where: CartItemWhereUniqueInput! + update: CartItemUpdateWithoutUserDataInput! + create: CartItemCreateWithoutUserInput! +} + +input CartItemWhereInput { + """Logical AND on all given filters.""" + AND: [CartItemWhereInput!] + + """Logical OR on all given filters.""" + OR: [CartItemWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [CartItemWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + quantity: Int + + """All values that are not equal to given value.""" + quantity_not: Int + + """All values that are contained in given list.""" + quantity_in: [Int!] + + """All values that are not contained in given list.""" + quantity_not_in: [Int!] + + """All values less than the given value.""" + quantity_lt: Int + + """All values less than or equal the given value.""" + quantity_lte: Int + + """All values greater than the given value.""" + quantity_gt: Int + + """All values greater than or equal the given value.""" + quantity_gte: Int + item: ItemWhereInput + user: UserWhereInput +} + +input CartItemWhereUniqueInput { + id: ID +} + +scalar DateTime + +type Item implements Node { + id: ID! + title: String! + description: String! + image: String + largeImage: String + price: Int! + user(where: UserWhereInput): User! +} + +"""A connection to a list of items.""" +type ItemConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [ItemEdge]! + aggregate: AggregateItem! +} + +input ItemCreateInput { + title: String! + description: String! + image: String + largeImage: String + price: Int! + user: UserCreateOneInput! +} + +input ItemCreateOneInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput +} + +"""An edge in a connection.""" +type ItemEdge { + """The item at the end of the edge.""" + node: Item! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum ItemOrderByInput { + id_ASC + id_DESC + title_ASC + title_DESC + description_ASC + description_DESC + image_ASC + image_DESC + largeImage_ASC + largeImage_DESC + price_ASC + price_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type ItemPreviousValues { + id: ID! + title: String! + description: String! + image: String + largeImage: String + price: Int! +} + +type ItemSubscriptionPayload { + mutation: MutationType! + node: Item + updatedFields: [String!] + previousValues: ItemPreviousValues +} + +input ItemSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [ItemSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [ItemSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [ItemSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: ItemWhereInput +} + +input ItemUpdateDataInput { + title: String + description: String + image: String + largeImage: String + price: Int + user: UserUpdateOneInput +} + +input ItemUpdateInput { + title: String + description: String + image: String + largeImage: String + price: Int + user: UserUpdateOneInput +} + +input ItemUpdateOneInput { + create: ItemCreateInput + connect: ItemWhereUniqueInput + disconnect: Boolean + delete: Boolean + update: ItemUpdateDataInput + upsert: ItemUpsertNestedInput +} + +input ItemUpsertNestedInput { + update: ItemUpdateDataInput! + create: ItemCreateInput! +} + +input ItemWhereInput { + """Logical AND on all given filters.""" + AND: [ItemWhereInput!] + + """Logical OR on all given filters.""" + OR: [ItemWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [ItemWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + title: String + + """All values that are not equal to given value.""" + title_not: String + + """All values that are contained in given list.""" + title_in: [String!] + + """All values that are not contained in given list.""" + title_not_in: [String!] + + """All values less than the given value.""" + title_lt: String + + """All values less than or equal the given value.""" + title_lte: String + + """All values greater than the given value.""" + title_gt: String + + """All values greater than or equal the given value.""" + title_gte: String + + """All values containing the given string.""" + title_contains: String + + """All values not containing the given string.""" + title_not_contains: String + + """All values starting with the given string.""" + title_starts_with: String + + """All values not starting with the given string.""" + title_not_starts_with: String + + """All values ending with the given string.""" + title_ends_with: String + + """All values not ending with the given string.""" + title_not_ends_with: String + description: String + + """All values that are not equal to given value.""" + description_not: String + + """All values that are contained in given list.""" + description_in: [String!] + + """All values that are not contained in given list.""" + description_not_in: [String!] + + """All values less than the given value.""" + description_lt: String + + """All values less than or equal the given value.""" + description_lte: String + + """All values greater than the given value.""" + description_gt: String + + """All values greater than or equal the given value.""" + description_gte: String + + """All values containing the given string.""" + description_contains: String + + """All values not containing the given string.""" + description_not_contains: String + + """All values starting with the given string.""" + description_starts_with: String + + """All values not starting with the given string.""" + description_not_starts_with: String + + """All values ending with the given string.""" + description_ends_with: String + + """All values not ending with the given string.""" + description_not_ends_with: String + image: String + + """All values that are not equal to given value.""" + image_not: String + + """All values that are contained in given list.""" + image_in: [String!] + + """All values that are not contained in given list.""" + image_not_in: [String!] + + """All values less than the given value.""" + image_lt: String + + """All values less than or equal the given value.""" + image_lte: String + + """All values greater than the given value.""" + image_gt: String + + """All values greater than or equal the given value.""" + image_gte: String + + """All values containing the given string.""" + image_contains: String + + """All values not containing the given string.""" + image_not_contains: String + + """All values starting with the given string.""" + image_starts_with: String + + """All values not starting with the given string.""" + image_not_starts_with: String + + """All values ending with the given string.""" + image_ends_with: String + + """All values not ending with the given string.""" + image_not_ends_with: String + largeImage: String + + """All values that are not equal to given value.""" + largeImage_not: String + + """All values that are contained in given list.""" + largeImage_in: [String!] + + """All values that are not contained in given list.""" + largeImage_not_in: [String!] + + """All values less than the given value.""" + largeImage_lt: String + + """All values less than or equal the given value.""" + largeImage_lte: String + + """All values greater than the given value.""" + largeImage_gt: String + + """All values greater than or equal the given value.""" + largeImage_gte: String + + """All values containing the given string.""" + largeImage_contains: String + + """All values not containing the given string.""" + largeImage_not_contains: String + + """All values starting with the given string.""" + largeImage_starts_with: String + + """All values not starting with the given string.""" + largeImage_not_starts_with: String + + """All values ending with the given string.""" + largeImage_ends_with: String + + """All values not ending with the given string.""" + largeImage_not_ends_with: String + price: Int + + """All values that are not equal to given value.""" + price_not: Int + + """All values that are contained in given list.""" + price_in: [Int!] + + """All values that are not contained in given list.""" + price_not_in: [Int!] + + """All values less than the given value.""" + price_lt: Int + + """All values less than or equal the given value.""" + price_lte: Int + + """All values greater than the given value.""" + price_gt: Int + + """All values greater than or equal the given value.""" + price_gte: Int + user: UserWhereInput +} + +input ItemWhereUniqueInput { + id: ID +} + +""" +The `Long` scalar type represents non-fractional signed whole numeric values. +Long can represent values between -(2^63) and 2^63 - 1. +""" +scalar Long + +type Mutation { + createCartItem(data: CartItemCreateInput!): CartItem! + createOrder(data: OrderCreateInput!): Order! + createItem(data: ItemCreateInput!): Item! + createOrderItem(data: OrderItemCreateInput!): OrderItem! + createUser(data: UserCreateInput!): User! + updateCartItem(data: CartItemUpdateInput!, where: CartItemWhereUniqueInput!): CartItem + updateOrder(data: OrderUpdateInput!, where: OrderWhereUniqueInput!): Order + updateItem(data: ItemUpdateInput!, where: ItemWhereUniqueInput!): Item + updateOrderItem(data: OrderItemUpdateInput!, where: OrderItemWhereUniqueInput!): OrderItem + updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User + deleteCartItem(where: CartItemWhereUniqueInput!): CartItem + deleteOrder(where: OrderWhereUniqueInput!): Order + deleteItem(where: ItemWhereUniqueInput!): Item + deleteOrderItem(where: OrderItemWhereUniqueInput!): OrderItem + deleteUser(where: UserWhereUniqueInput!): User + upsertCartItem(where: CartItemWhereUniqueInput!, create: CartItemCreateInput!, update: CartItemUpdateInput!): CartItem! + upsertOrder(where: OrderWhereUniqueInput!, create: OrderCreateInput!, update: OrderUpdateInput!): Order! + upsertItem(where: ItemWhereUniqueInput!, create: ItemCreateInput!, update: ItemUpdateInput!): Item! + upsertOrderItem(where: OrderItemWhereUniqueInput!, create: OrderItemCreateInput!, update: OrderItemUpdateInput!): OrderItem! + upsertUser(where: UserWhereUniqueInput!, create: UserCreateInput!, update: UserUpdateInput!): User! + updateManyCartItems(data: CartItemUpdateInput!, where: CartItemWhereInput): BatchPayload! + updateManyOrders(data: OrderUpdateInput!, where: OrderWhereInput): BatchPayload! + updateManyItems(data: ItemUpdateInput!, where: ItemWhereInput): BatchPayload! + updateManyOrderItems(data: OrderItemUpdateInput!, where: OrderItemWhereInput): BatchPayload! + updateManyUsers(data: UserUpdateInput!, where: UserWhereInput): BatchPayload! + deleteManyCartItems(where: CartItemWhereInput): BatchPayload! + deleteManyOrders(where: OrderWhereInput): BatchPayload! + deleteManyItems(where: ItemWhereInput): BatchPayload! + deleteManyOrderItems(where: OrderItemWhereInput): BatchPayload! + deleteManyUsers(where: UserWhereInput): BatchPayload! +} + +enum MutationType { + CREATED + UPDATED + DELETED +} + +"""An object with an ID""" +interface Node { + """The id of the object.""" + id: ID! +} + +type Order implements Node { + id: ID! + items(where: OrderItemWhereInput, orderBy: OrderItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [OrderItem!] + total: Int! + user(where: UserWhereInput): User! + charge: String! + createdAt: DateTime! + updatedAt: DateTime! +} + +"""A connection to a list of items.""" +type OrderConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [OrderEdge]! + aggregate: AggregateOrder! +} + +input OrderCreateInput { + total: Int! + charge: String! + items: OrderItemCreateManyInput + user: UserCreateOneInput! +} + +"""An edge in a connection.""" +type OrderEdge { + """The item at the end of the edge.""" + node: Order! + + """A cursor for use in pagination.""" + cursor: String! +} + +type OrderItem implements Node { + id: ID! + title: String! + description: String! + image: String! + largeImage: String! + price: Int! + quantity: Int! + user(where: UserWhereInput): User +} + +"""A connection to a list of items.""" +type OrderItemConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [OrderItemEdge]! + aggregate: AggregateOrderItem! +} + +input OrderItemCreateInput { + title: String! + description: String! + image: String! + largeImage: String! + price: Int! + quantity: Int + user: UserCreateOneInput +} + +input OrderItemCreateManyInput { + create: [OrderItemCreateInput!] + connect: [OrderItemWhereUniqueInput!] +} + +"""An edge in a connection.""" +type OrderItemEdge { + """The item at the end of the edge.""" + node: OrderItem! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum OrderItemOrderByInput { + id_ASC + id_DESC + title_ASC + title_DESC + description_ASC + description_DESC + image_ASC + image_DESC + largeImage_ASC + largeImage_DESC + price_ASC + price_DESC + quantity_ASC + quantity_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type OrderItemPreviousValues { + id: ID! + title: String! + description: String! + image: String! + largeImage: String! + price: Int! + quantity: Int! +} + +type OrderItemSubscriptionPayload { + mutation: MutationType! + node: OrderItem + updatedFields: [String!] + previousValues: OrderItemPreviousValues +} + +input OrderItemSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [OrderItemSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [OrderItemSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [OrderItemSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: OrderItemWhereInput +} + +input OrderItemUpdateDataInput { + title: String + description: String + image: String + largeImage: String + price: Int + quantity: Int + user: UserUpdateOneInput +} + +input OrderItemUpdateInput { + title: String + description: String + image: String + largeImage: String + price: Int + quantity: Int + user: UserUpdateOneInput +} + +input OrderItemUpdateManyInput { + create: [OrderItemCreateInput!] + connect: [OrderItemWhereUniqueInput!] + disconnect: [OrderItemWhereUniqueInput!] + delete: [OrderItemWhereUniqueInput!] + update: [OrderItemUpdateWithWhereUniqueNestedInput!] + upsert: [OrderItemUpsertWithWhereUniqueNestedInput!] +} + +input OrderItemUpdateWithWhereUniqueNestedInput { + where: OrderItemWhereUniqueInput! + data: OrderItemUpdateDataInput! +} + +input OrderItemUpsertWithWhereUniqueNestedInput { + where: OrderItemWhereUniqueInput! + update: OrderItemUpdateDataInput! + create: OrderItemCreateInput! +} + +input OrderItemWhereInput { + """Logical AND on all given filters.""" + AND: [OrderItemWhereInput!] + + """Logical OR on all given filters.""" + OR: [OrderItemWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [OrderItemWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + title: String + + """All values that are not equal to given value.""" + title_not: String + + """All values that are contained in given list.""" + title_in: [String!] + + """All values that are not contained in given list.""" + title_not_in: [String!] + + """All values less than the given value.""" + title_lt: String + + """All values less than or equal the given value.""" + title_lte: String + + """All values greater than the given value.""" + title_gt: String + + """All values greater than or equal the given value.""" + title_gte: String + + """All values containing the given string.""" + title_contains: String + + """All values not containing the given string.""" + title_not_contains: String + + """All values starting with the given string.""" + title_starts_with: String + + """All values not starting with the given string.""" + title_not_starts_with: String + + """All values ending with the given string.""" + title_ends_with: String + + """All values not ending with the given string.""" + title_not_ends_with: String + description: String + + """All values that are not equal to given value.""" + description_not: String + + """All values that are contained in given list.""" + description_in: [String!] + + """All values that are not contained in given list.""" + description_not_in: [String!] + + """All values less than the given value.""" + description_lt: String + + """All values less than or equal the given value.""" + description_lte: String + + """All values greater than the given value.""" + description_gt: String + + """All values greater than or equal the given value.""" + description_gte: String + + """All values containing the given string.""" + description_contains: String + + """All values not containing the given string.""" + description_not_contains: String + + """All values starting with the given string.""" + description_starts_with: String + + """All values not starting with the given string.""" + description_not_starts_with: String + + """All values ending with the given string.""" + description_ends_with: String + + """All values not ending with the given string.""" + description_not_ends_with: String + image: String + + """All values that are not equal to given value.""" + image_not: String + + """All values that are contained in given list.""" + image_in: [String!] + + """All values that are not contained in given list.""" + image_not_in: [String!] + + """All values less than the given value.""" + image_lt: String + + """All values less than or equal the given value.""" + image_lte: String + + """All values greater than the given value.""" + image_gt: String + + """All values greater than or equal the given value.""" + image_gte: String + + """All values containing the given string.""" + image_contains: String + + """All values not containing the given string.""" + image_not_contains: String + + """All values starting with the given string.""" + image_starts_with: String + + """All values not starting with the given string.""" + image_not_starts_with: String + + """All values ending with the given string.""" + image_ends_with: String + + """All values not ending with the given string.""" + image_not_ends_with: String + largeImage: String + + """All values that are not equal to given value.""" + largeImage_not: String + + """All values that are contained in given list.""" + largeImage_in: [String!] + + """All values that are not contained in given list.""" + largeImage_not_in: [String!] + + """All values less than the given value.""" + largeImage_lt: String + + """All values less than or equal the given value.""" + largeImage_lte: String + + """All values greater than the given value.""" + largeImage_gt: String + + """All values greater than or equal the given value.""" + largeImage_gte: String + + """All values containing the given string.""" + largeImage_contains: String + + """All values not containing the given string.""" + largeImage_not_contains: String + + """All values starting with the given string.""" + largeImage_starts_with: String + + """All values not starting with the given string.""" + largeImage_not_starts_with: String + + """All values ending with the given string.""" + largeImage_ends_with: String + + """All values not ending with the given string.""" + largeImage_not_ends_with: String + price: Int + + """All values that are not equal to given value.""" + price_not: Int + + """All values that are contained in given list.""" + price_in: [Int!] + + """All values that are not contained in given list.""" + price_not_in: [Int!] + + """All values less than the given value.""" + price_lt: Int + + """All values less than or equal the given value.""" + price_lte: Int + + """All values greater than the given value.""" + price_gt: Int + + """All values greater than or equal the given value.""" + price_gte: Int + quantity: Int + + """All values that are not equal to given value.""" + quantity_not: Int + + """All values that are contained in given list.""" + quantity_in: [Int!] + + """All values that are not contained in given list.""" + quantity_not_in: [Int!] + + """All values less than the given value.""" + quantity_lt: Int + + """All values less than or equal the given value.""" + quantity_lte: Int + + """All values greater than the given value.""" + quantity_gt: Int + + """All values greater than or equal the given value.""" + quantity_gte: Int + user: UserWhereInput +} + +input OrderItemWhereUniqueInput { + id: ID +} + +enum OrderOrderByInput { + id_ASC + id_DESC + total_ASC + total_DESC + charge_ASC + charge_DESC + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC +} + +type OrderPreviousValues { + id: ID! + total: Int! + charge: String! + createdAt: DateTime! + updatedAt: DateTime! +} + +type OrderSubscriptionPayload { + mutation: MutationType! + node: Order + updatedFields: [String!] + previousValues: OrderPreviousValues +} + +input OrderSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [OrderSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [OrderSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [OrderSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: OrderWhereInput +} + +input OrderUpdateInput { + total: Int + charge: String + items: OrderItemUpdateManyInput + user: UserUpdateOneInput +} + +input OrderWhereInput { + """Logical AND on all given filters.""" + AND: [OrderWhereInput!] + + """Logical OR on all given filters.""" + OR: [OrderWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [OrderWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + total: Int + + """All values that are not equal to given value.""" + total_not: Int + + """All values that are contained in given list.""" + total_in: [Int!] + + """All values that are not contained in given list.""" + total_not_in: [Int!] + + """All values less than the given value.""" + total_lt: Int + + """All values less than or equal the given value.""" + total_lte: Int + + """All values greater than the given value.""" + total_gt: Int + + """All values greater than or equal the given value.""" + total_gte: Int + charge: String + + """All values that are not equal to given value.""" + charge_not: String + + """All values that are contained in given list.""" + charge_in: [String!] + + """All values that are not contained in given list.""" + charge_not_in: [String!] + + """All values less than the given value.""" + charge_lt: String + + """All values less than or equal the given value.""" + charge_lte: String + + """All values greater than the given value.""" + charge_gt: String + + """All values greater than or equal the given value.""" + charge_gte: String + + """All values containing the given string.""" + charge_contains: String + + """All values not containing the given string.""" + charge_not_contains: String + + """All values starting with the given string.""" + charge_starts_with: String + + """All values not starting with the given string.""" + charge_not_starts_with: String + + """All values ending with the given string.""" + charge_ends_with: String + + """All values not ending with the given string.""" + charge_not_ends_with: String + createdAt: DateTime + + """All values that are not equal to given value.""" + createdAt_not: DateTime + + """All values that are contained in given list.""" + createdAt_in: [DateTime!] + + """All values that are not contained in given list.""" + createdAt_not_in: [DateTime!] + + """All values less than the given value.""" + createdAt_lt: DateTime + + """All values less than or equal the given value.""" + createdAt_lte: DateTime + + """All values greater than the given value.""" + createdAt_gt: DateTime + + """All values greater than or equal the given value.""" + createdAt_gte: DateTime + updatedAt: DateTime + + """All values that are not equal to given value.""" + updatedAt_not: DateTime + + """All values that are contained in given list.""" + updatedAt_in: [DateTime!] + + """All values that are not contained in given list.""" + updatedAt_not_in: [DateTime!] + + """All values less than the given value.""" + updatedAt_lt: DateTime + + """All values less than or equal the given value.""" + updatedAt_lte: DateTime + + """All values greater than the given value.""" + updatedAt_gt: DateTime + + """All values greater than or equal the given value.""" + updatedAt_gte: DateTime + items_every: OrderItemWhereInput + items_some: OrderItemWhereInput + items_none: OrderItemWhereInput + user: UserWhereInput +} + +input OrderWhereUniqueInput { + id: ID +} + +"""Information about pagination in a connection.""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String +} + +enum Permission { + ADMIN + USER + ITEMCREATE + ITEMUPDATE + ITEMDELETE + PERMISSIONUPDATE +} + +type Query { + cartItems(where: CartItemWhereInput, orderBy: CartItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [CartItem]! + orders(where: OrderWhereInput, orderBy: OrderOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Order]! + items(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Item]! + orderItems(where: OrderItemWhereInput, orderBy: OrderItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [OrderItem]! + users(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]! + cartItem(where: CartItemWhereUniqueInput!): CartItem + order(where: OrderWhereUniqueInput!): Order + item(where: ItemWhereUniqueInput!): Item + orderItem(where: OrderItemWhereUniqueInput!): OrderItem + user(where: UserWhereUniqueInput!): User + cartItemsConnection(where: CartItemWhereInput, orderBy: CartItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): CartItemConnection! + ordersConnection(where: OrderWhereInput, orderBy: OrderOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): OrderConnection! + itemsConnection(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): ItemConnection! + orderItemsConnection(where: OrderItemWhereInput, orderBy: OrderItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): OrderItemConnection! + usersConnection(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): UserConnection! + + """Fetches an object given its ID""" + node( + """The ID of an object""" + id: ID! + ): Node +} + +type Subscription { + cartItem(where: CartItemSubscriptionWhereInput): CartItemSubscriptionPayload + order(where: OrderSubscriptionWhereInput): OrderSubscriptionPayload + item(where: ItemSubscriptionWhereInput): ItemSubscriptionPayload + orderItem(where: OrderItemSubscriptionWhereInput): OrderItemSubscriptionPayload + user(where: UserSubscriptionWhereInput): UserSubscriptionPayload +} + +type User implements Node { + id: ID! + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: [Permission!]! + cart(where: CartItemWhereInput, orderBy: CartItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [CartItem!] +} + +"""A connection to a list of items.""" +type UserConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [UserEdge]! + aggregate: AggregateUser! +} + +input UserCreateInput { + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: UserCreatepermissionsInput + cart: CartItemCreateManyWithoutUserInput +} + +input UserCreateOneInput { + create: UserCreateInput + connect: UserWhereUniqueInput +} + +input UserCreateOneWithoutCartInput { + create: UserCreateWithoutCartInput + connect: UserWhereUniqueInput +} + +input UserCreatepermissionsInput { + set: [Permission!] +} + +input UserCreateWithoutCartInput { + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: UserCreatepermissionsInput +} + +"""An edge in a connection.""" +type UserEdge { + """The item at the end of the edge.""" + node: User! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum UserOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + email_ASC + email_DESC + password_ASC + password_DESC + resetToken_ASC + resetToken_DESC + resetTokenExpiry_ASC + resetTokenExpiry_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type UserPreviousValues { + id: ID! + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: [Permission!]! +} + +type UserSubscriptionPayload { + mutation: MutationType! + node: User + updatedFields: [String!] + previousValues: UserPreviousValues +} + +input UserSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [UserSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [UserSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [UserSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: UserWhereInput +} + +input UserUpdateDataInput { + name: String + email: String + password: String + resetToken: String + resetTokenExpiry: String + permissions: UserUpdatepermissionsInput + cart: CartItemUpdateManyWithoutUserInput +} + +input UserUpdateInput { + name: String + email: String + password: String + resetToken: String + resetTokenExpiry: String + permissions: UserUpdatepermissionsInput + cart: CartItemUpdateManyWithoutUserInput +} + +input UserUpdateOneInput { + create: UserCreateInput + connect: UserWhereUniqueInput + delete: Boolean + update: UserUpdateDataInput + upsert: UserUpsertNestedInput +} + +input UserUpdateOneWithoutCartInput { + create: UserCreateWithoutCartInput + connect: UserWhereUniqueInput + delete: Boolean + update: UserUpdateWithoutCartDataInput + upsert: UserUpsertWithoutCartInput +} + +input UserUpdatepermissionsInput { + set: [Permission!] +} + +input UserUpdateWithoutCartDataInput { + name: String + email: String + password: String + resetToken: String + resetTokenExpiry: String + permissions: UserUpdatepermissionsInput +} + +input UserUpsertNestedInput { + update: UserUpdateDataInput! + create: UserCreateInput! +} + +input UserUpsertWithoutCartInput { + update: UserUpdateWithoutCartDataInput! + create: UserCreateWithoutCartInput! +} + +input UserWhereInput { + """Logical AND on all given filters.""" + AND: [UserWhereInput!] + + """Logical OR on all given filters.""" + OR: [UserWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [UserWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + name: String + + """All values that are not equal to given value.""" + name_not: String + + """All values that are contained in given list.""" + name_in: [String!] + + """All values that are not contained in given list.""" + name_not_in: [String!] + + """All values less than the given value.""" + name_lt: String + + """All values less than or equal the given value.""" + name_lte: String + + """All values greater than the given value.""" + name_gt: String + + """All values greater than or equal the given value.""" + name_gte: String + + """All values containing the given string.""" + name_contains: String + + """All values not containing the given string.""" + name_not_contains: String + + """All values starting with the given string.""" + name_starts_with: String + + """All values not starting with the given string.""" + name_not_starts_with: String + + """All values ending with the given string.""" + name_ends_with: String + + """All values not ending with the given string.""" + name_not_ends_with: String + email: String + + """All values that are not equal to given value.""" + email_not: String + + """All values that are contained in given list.""" + email_in: [String!] + + """All values that are not contained in given list.""" + email_not_in: [String!] + + """All values less than the given value.""" + email_lt: String + + """All values less than or equal the given value.""" + email_lte: String + + """All values greater than the given value.""" + email_gt: String + + """All values greater than or equal the given value.""" + email_gte: String + + """All values containing the given string.""" + email_contains: String + + """All values not containing the given string.""" + email_not_contains: String + + """All values starting with the given string.""" + email_starts_with: String + + """All values not starting with the given string.""" + email_not_starts_with: String + + """All values ending with the given string.""" + email_ends_with: String + + """All values not ending with the given string.""" + email_not_ends_with: String + password: String + + """All values that are not equal to given value.""" + password_not: String + + """All values that are contained in given list.""" + password_in: [String!] + + """All values that are not contained in given list.""" + password_not_in: [String!] + + """All values less than the given value.""" + password_lt: String + + """All values less than or equal the given value.""" + password_lte: String + + """All values greater than the given value.""" + password_gt: String + + """All values greater than or equal the given value.""" + password_gte: String + + """All values containing the given string.""" + password_contains: String + + """All values not containing the given string.""" + password_not_contains: String + + """All values starting with the given string.""" + password_starts_with: String + + """All values not starting with the given string.""" + password_not_starts_with: String + + """All values ending with the given string.""" + password_ends_with: String + + """All values not ending with the given string.""" + password_not_ends_with: String + resetToken: String + + """All values that are not equal to given value.""" + resetToken_not: String + + """All values that are contained in given list.""" + resetToken_in: [String!] + + """All values that are not contained in given list.""" + resetToken_not_in: [String!] + + """All values less than the given value.""" + resetToken_lt: String + + """All values less than or equal the given value.""" + resetToken_lte: String + + """All values greater than the given value.""" + resetToken_gt: String + + """All values greater than or equal the given value.""" + resetToken_gte: String + + """All values containing the given string.""" + resetToken_contains: String + + """All values not containing the given string.""" + resetToken_not_contains: String + + """All values starting with the given string.""" + resetToken_starts_with: String + + """All values not starting with the given string.""" + resetToken_not_starts_with: String + + """All values ending with the given string.""" + resetToken_ends_with: String + + """All values not ending with the given string.""" + resetToken_not_ends_with: String + resetTokenExpiry: String + + """All values that are not equal to given value.""" + resetTokenExpiry_not: String + + """All values that are contained in given list.""" + resetTokenExpiry_in: [String!] + + """All values that are not contained in given list.""" + resetTokenExpiry_not_in: [String!] + + """All values less than the given value.""" + resetTokenExpiry_lt: String + + """All values less than or equal the given value.""" + resetTokenExpiry_lte: String + + """All values greater than the given value.""" + resetTokenExpiry_gt: String + + """All values greater than or equal the given value.""" + resetTokenExpiry_gte: String + + """All values containing the given string.""" + resetTokenExpiry_contains: String + + """All values not containing the given string.""" + resetTokenExpiry_not_contains: String + + """All values starting with the given string.""" + resetTokenExpiry_starts_with: String + + """All values not starting with the given string.""" + resetTokenExpiry_not_starts_with: String + + """All values ending with the given string.""" + resetTokenExpiry_ends_with: String + + """All values not ending with the given string.""" + resetTokenExpiry_not_ends_with: String + cart_every: CartItemWhereInput + cart_some: CartItemWhereInput + cart_none: CartItemWhereInput +} + +input UserWhereUniqueInput { + id: ID + email: String +} diff --git a/stepped-solutions/53/backend/src/resolvers/Query.js b/stepped-solutions/53/backend/src/resolvers/Query.js new file mode 100755 index 0000000..8e0f169 --- /dev/null +++ b/stepped-solutions/53/backend/src/resolvers/Query.js @@ -0,0 +1,55 @@ +const { forwardTo } = require('prisma-binding'); +const { hasPermission } = require('../utils'); + +const Query = { + items: forwardTo('db'), + item: forwardTo('db'), + itemsConnection: forwardTo('db'), + me(parent, args, ctx, info) { + // check if there is a current user ID + if (!ctx.request.userId) { + return null; + } + return ctx.db.query.user( + { + where: { id: ctx.request.userId }, + }, + info + ); + }, + async users(parent, args, ctx, info) { + // 1. Check if they are logged in + if (!ctx.request.userId) { + throw new Error('You must be logged in!'); + } + console.log(ctx.request.userId); + // 2. Check if the user has the permissions to query all the users + hasPermission(ctx.request.user, ['ADMIN', 'PERMISSIONUPDATE']); + + // 2. if they do, query all the users! + return ctx.db.query.users({}, info); + }, + async order(parent, args, ctx, info) { + // 1. Make sure they are logged in + if (!ctx.request.userId) { + throw new Error('You arent logged in!'); + } + // 2. Query the current order + const order = await ctx.db.query.order( + { + where: { id: args.id }, + }, + info + ); + // 3. Check if the have the permissions to see this order + const ownsOrder = order.user.id === ctx.request.userId; + const hasPermissionToSeeOrder = ctx.request.user.permissions.includes('ADMIN'); + if (!ownsOrder || !hasPermission) { + throw new Error('You cant see this buddd'); + } + // 4. Return the order + return order; + }, +}; + +module.exports = Query; diff --git a/stepped-solutions/53/backend/src/schema.graphql b/stepped-solutions/53/backend/src/schema.graphql new file mode 100755 index 0000000..15d119b --- /dev/null +++ b/stepped-solutions/53/backend/src/schema.graphql @@ -0,0 +1,37 @@ +# import * from './generated/prisma.graphql' + +type SuccessMessage { + message: String +} + +type Mutation { + createItem(title: String, description: String, price: Int, image: String, largeImage: String): Item! + updateItem(id: ID!, title: String, description: String, price: Int): Item! + deleteItem(id: ID!): Item + signup(email: String!, password: String!, name: String!): User! + signin(email: String!, password: String!): User! + signout: SuccessMessage + requestReset(email: String!): SuccessMessage + resetPassword(resetToken: String!, password: String!, confirmPassword: String!): User! + updatePermissions(permissions: [Permission], userId: ID!): User + addToCart(id: ID!): CartItem + removeFromCart(id: ID!): CartItem + createOrder(token: String!): Order! +} + +type Query { + items(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, first: Int): [Item]! + item(where: ItemWhereUniqueInput!): Item + itemsConnection(where: ItemWhereInput): ItemConnection! + me: User + users: [User]! + order(id: ID!): Order +} + +type User{ + id: ID! + name: String! + email: String! + permissions: [Permission!]! + cart: [CartItem!]! +} diff --git a/stepped-solutions/53/frontend/components/Cart.js b/stepped-solutions/53/frontend/components/Cart.js new file mode 100755 index 0000000..2a72b38 --- /dev/null +++ b/stepped-solutions/53/frontend/components/Cart.js @@ -0,0 +1,66 @@ +import React from 'react'; +import { Query, Mutation } from 'react-apollo'; +import gql from 'graphql-tag'; +import { adopt } from 'react-adopt'; +import User from './User'; +import CartStyles from './styles/CartStyles'; +import Supreme from './styles/Supreme'; +import CloseButton from './styles/CloseButton'; +import SickButton from './styles/SickButton'; +import CartItem from './CartItem'; +import calcTotalPrice from '../lib/calcTotalPrice'; +import formatMoney from '../lib/formatMoney'; +import TakeMyMoney from './TakeMyMoney'; + +const LOCAL_STATE_QUERY = gql` + query { + cartOpen @client + } +`; + +const TOGGLE_CART_MUTATION = gql` + mutation { + toggleCart @client + } +`; +/* eslint-disable */ +const Composed = adopt({ + user: ({ render }) => <User>{render}</User>, + toggleCart: ({ render }) => <Mutation mutation={TOGGLE_CART_MUTATION}>{render}</Mutation>, + localState: ({ render }) => <Query query={LOCAL_STATE_QUERY}>{render}</Query>, +}); +/* eslint-enable */ + +const Cart = () => ( + <Composed> + {({ user, toggleCart, localState }) => { + const me = user.data.me; + if (!me) return null; + return ( + <CartStyles open={localState.data.cartOpen}> + <header> + <CloseButton onClick={toggleCart} title="close"> + × + </CloseButton> + <Supreme>{me.name}'s Cart</Supreme> + <p> + You Have {me.cart.length} Item{me.cart.length === 1 ? '' : 's'} in your cart. + </p> + </header> + <ul>{me.cart.map(cartItem => <CartItem key={cartItem.id} cartItem={cartItem} />)}</ul> + <footer> + <p>{formatMoney(calcTotalPrice(me.cart))}</p> + {me.cart.length && ( + <TakeMyMoney> + <SickButton>Checkout</SickButton> + </TakeMyMoney> + )} + </footer> + </CartStyles> + ); + }} + </Composed> +); + +export default Cart; +export { LOCAL_STATE_QUERY, TOGGLE_CART_MUTATION }; diff --git a/stepped-solutions/53/frontend/components/Order.js b/stepped-solutions/53/frontend/components/Order.js new file mode 100755 index 0000000..f2a2caf --- /dev/null +++ b/stepped-solutions/53/frontend/components/Order.js @@ -0,0 +1,91 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Query } from 'react-apollo'; +import { format } from 'date-fns'; +import Head from 'next/head'; +import gql from 'graphql-tag'; +import formatMoney from '../lib/formatMoney'; +import Error from './ErrorMessage'; +import OrderStyles from './styles/OrderStyles'; + +const SINGLE_ORDER_QUERY = gql` + query SINGLE_ORDER_QUERY($id: ID!) { + order(id: $id) { + id + charge + total + createdAt + user { + id + } + items { + id + title + description + price + image + quantity + } + } + } +`; + +class Order extends React.Component { + static propTypes = { + id: PropTypes.string.isRequired, + }; + render() { + return ( + <Query query={SINGLE_ORDER_QUERY} variables={{ id: this.props.id }}> + {({ data, error, loading }) => { + if (error) return <Error error={error} />; + if (loading) return <p>Loading...</p>; + const order = data.order; + return ( + <OrderStyles> + <Head> + <title>Sick Fits - Order {order.id}</title> + </Head> + <p> + <span>Order ID:</span> + <span>{this.props.id}</span> + </p> + <p> + <span>Charge</span> + <span>{order.charge}</span> + </p> + <p> + <span>Date</span> + <span>{format(order.createdAt, 'MMMM d, YYYY h:mm a')}</span> + </p> + <p> + <span>Order Total</span> + <span>{formatMoney(order.total)}</span> + </p> + <p> + <span>Item Count</span> + <span>{order.items.length}</span> + </p> + <div className="items"> + {order.items.map(item => ( + <div className="order-item" key={item.id}> + <img src={item.image} alt={item.title} /> + <div className="item-details"> + <h2>{item.title}</h2> + <p>Qty: {item.quantity}</p> + <p>Each: {formatMoney(item.price)}</p> + <p>SubTotal: {formatMoney(item.price * item.quantity)}</p> + <p>{item.description}</p> + </div> + </div> + ))} + </div> + </OrderStyles> + ); + }} + </Query> + ); + } +} + +export default Order; diff --git a/stepped-solutions/53/frontend/components/Search.js b/stepped-solutions/53/frontend/components/Search.js new file mode 100755 index 0000000..c29f93e --- /dev/null +++ b/stepped-solutions/53/frontend/components/Search.js @@ -0,0 +1,94 @@ +import React from 'react'; +import Downshift, { resetIdCounter } from 'downshift'; +import Router from 'next/router'; +import { ApolloConsumer } from 'react-apollo'; +import gql from 'graphql-tag'; +import debounce from 'lodash.debounce'; +import { DropDown, DropDownItem, SearchStyles } from './styles/DropDown'; + +const SEARCH_ITEMS_QUERY = gql` + query SEARCH_ITEMS_QUERY($searchTerm: String!) { + items(where: { OR: [{ title_contains: $searchTerm }, { description_contains: $searchTerm }] }) { + id + image + title + } + } +`; + +function routeToItem(item) { + Router.push({ + pathname: '/item', + query: { + id: item.id, + }, + }); +} + +class AutoComplete extends React.Component { + state = { + items: [], + loading: false, + }; + onChange = debounce(async (e, client) => { + console.log('Searching...'); + // turn loading on + this.setState({ loading: true }); + // Manually query apollo client + const res = await client.query({ + query: SEARCH_ITEMS_QUERY, + variables: { searchTerm: e.target.value }, + }); + this.setState({ + items: res.data.items, + loading: false, + }); + }, 350); + render() { + resetIdCounter(); + return ( + <SearchStyles> + <Downshift onChange={routeToItem} itemToString={item => (item === null ? '' : item.title)}> + {({ getInputProps, getItemProps, isOpen, inputValue, highlightedIndex }) => ( + <div> + <ApolloConsumer> + {client => ( + <input + {...getInputProps({ + type: 'search', + placeholder: 'Search For An Item', + id: 'search', + className: this.state.loading ? 'loading' : '', + onChange: e => { + e.persist(); + this.onChange(e, client); + }, + })} + /> + )} + </ApolloConsumer> + {isOpen && ( + <DropDown> + {this.state.items.map((item, index) => ( + <DropDownItem + {...getItemProps({ item })} + key={item.id} + highlighted={index === highlightedIndex} + > + <img width="50" src={item.image} alt={item.title} /> + {item.title} + </DropDownItem> + ))} + {!this.state.items.length && + !this.state.loading && <DropDownItem> Nothing Found {inputValue}</DropDownItem>} + </DropDown> + )} + </div> + )} + </Downshift> + </SearchStyles> + ); + } +} + +export default AutoComplete; diff --git a/stepped-solutions/53/frontend/components/TakeMyMoney.js b/stepped-solutions/53/frontend/components/TakeMyMoney.js new file mode 100755 index 0000000..9d6614e --- /dev/null +++ b/stepped-solutions/53/frontend/components/TakeMyMoney.js @@ -0,0 +1,77 @@ +import React from 'react'; +import StripeCheckout from 'react-stripe-checkout'; +import { Mutation } from 'react-apollo'; +import Router from 'next/router'; +import NProgress from 'nprogress'; +import PropTypes from 'prop-types'; +import gql from 'graphql-tag'; +import calcTotalPrice from '../lib/calcTotalPrice'; +import Error from './ErrorMessage'; +import User, { CURRENT_USER_QUERY } from './User'; + +const CREATE_ORDER_MUTATION = gql` + mutation createOrder($token: String!) { + createOrder(token: $token) { + id + charge + total + items { + id + title + } + } + } +`; + +function totalItems(cart) { + return cart.reduce((tally, cartItem) => tally + cartItem.quantity, 0); +} + +class TakeMyMoney extends React.Component { + onToken = async (res, createOrder) => { + NProgress.start(); + console.log('On Token Called!'); + console.log(res.id); + // manually call the mutation once we have the stripe token + const order = await createOrder({ + variables: { + token: res.id, + }, + }).catch(err => { + alert(err.message); + }); + Router.push({ + pathname: '/order', + query: { id: order.data.createOrder.id }, + }); + }; + render() { + return ( + <User> + {({ data: { me } }) => ( + <Mutation + mutation={CREATE_ORDER_MUTATION} + refetchQueries={[{ query: CURRENT_USER_QUERY }]} + > + {createOrder => ( + <StripeCheckout + amount={calcTotalPrice(me.cart)} + name="Sick Fits" + description={`Order of ${totalItems(me.cart)} items!`} + image={me.cart.length && me.cart[0].item && me.cart[0].item.image} + stripeKey="pk_test_Vtknn6vSdcZWSG2JWvEiWSqC" + currency="USD" + email={me.email} + token={res => this.onToken(res, createOrder)} + > + {this.props.children} + </StripeCheckout> + )} + </Mutation> + )} + </User> + ); + } +} + +export default TakeMyMoney; diff --git a/stepped-solutions/53/frontend/components/styles/OrderStyles.js b/stepped-solutions/53/frontend/components/styles/OrderStyles.js new file mode 100755 index 0000000..f461b70 --- /dev/null +++ b/stepped-solutions/53/frontend/components/styles/OrderStyles.js @@ -0,0 +1,37 @@ +import styled from 'styled-components'; + +const OrderStyles = styled.div` + max-width: 1000px; + margin: 0 auto; + border: 1px solid ${props => props.theme.offWhite}; + box-shadow: ${props => props.theme.bs}; + padding: 2rem; + border-top: 10px solid red; + & > p { + display: grid; + grid-template-columns: 1fr 5fr; + margin: 0; + border-bottom: 1px solid ${props => props.theme.offWhite}; + span { + padding: 1rem; + &:first-child { + font-weight: 900; + text-align: right; + } + } + } + .order-item { + border-bottom: 1px solid ${props => props.theme.offWhite}; + display: grid; + grid-template-columns: 300px 1fr; + align-items: center; + grid-gap: 2rem; + margin: 2rem 0; + padding-bottom: 2rem; + img { + width: 100%; + object-fit: cover; + } + } +`; +export default OrderStyles; diff --git a/stepped-solutions/53/frontend/pages/order.js b/stepped-solutions/53/frontend/pages/order.js new file mode 100755 index 0000000..0fea0c6 --- /dev/null +++ b/stepped-solutions/53/frontend/pages/order.js @@ -0,0 +1,12 @@ +import PleaseSignIn from '../components/PleaseSignIn'; +import Order from '../components/Order'; + +const OrderPage = props => ( + <div> + <PleaseSignIn> + <Order id={props.query.id} /> + </PleaseSignIn> + </div> +); + +export default OrderPage; |
