diff --git a/GraphQLServer/app.ts b/GraphQLServer/app.ts index 26d8ed6..9645863 100644 --- a/GraphQLServer/app.ts +++ b/GraphQLServer/app.ts @@ -7,180 +7,180 @@ import _ from 'underscore.ts'; const app = new Application(); app.use(async (ctx, next) => { - await next(); - const rt = ctx.response.headers.get('X-Response-Time'); - console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`); + await next(); + const rt = ctx.response.headers.get('X-Response-Time'); + console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`); }); app.use(async (ctx, next) => { - const start = Date.now(); - await next(); - const ms = Date.now() - start; - ctx.response.headers.set('X-Response-Time', `${ms}ms`); + const start = Date.now(); + await next(); + const ms = Date.now() - start; + ctx.response.headers.set('X-Response-Time', `${ms}ms`); }); const typeDefs = gql` - input CreateUserInput { - name: String! - email: String! - age: Int - } - - type User { - id: ID! - name: String! - email: String! - age: Int - } - - type Post { - id: ID! - title: String! - body: String! - published: Boolean! - author: User - } - - type SuccessOrError { - success: Boolean! - message: String - } - - type Query { - testInput(input: CreateUserInput!): User - me: User! - user(id: ID!): User - users: [User]! - post(id: ID!): Post - posts(query: String): [Post!]! - grades: [Int!]! - add(nums: [Int!]!): Int! - } - - type Mutation { - createUser(name: String!, email: String!, age: Int): User! - deleteUser(id: ID!): SuccessOrError! - createPost(title: String!, body: String!, published: Boolean!): Post! - } + input CreateUserInput { + name: String! + email: String! + age: Int + } + + type User { + id: ID! + name: String! + email: String! + age: Int + } + + type Post { + id: ID! + title: String! + body: String! + published: Boolean! + author: User + } + + type SuccessOrError { + success: Boolean! + message: String + } + + type Query { + testInput(input: CreateUserInput!): User + me: User! + user(id: ID!): User + users: [User]! + post(id: ID!): Post + posts(query: String): [Post!]! + grades: [Int!]! + add(nums: [Int!]!): Int! + } + + type Mutation { + createUser(name: String!, email: String!, age: Int): User! + deleteUser(id: ID!): SuccessOrError! + createPost(title: String!, body: String!, published: Boolean!): Post! + } `; // console.log(JSON.stringify(typeDefs, null, 2)); const resolvers = { - Query: { - testInput: async ( - parent: any, - { input }: { input: { name: string; email: string; age?: number } }, - context: any, - info: any - ) => { - return { id: 'wtf', ...input }; + Query: { + testInput: async ( + parent: any, + { input }: { input: { name: string; email: string; age?: number } }, + context: any, + info: any, + ) => { + return { id: 'wtf', ...input }; + }, + grades: async (parent: any, args: any, context: any, info: any) => { + return [1, 2, 3, 4, 5]; + }, + add: async ( + parent: any, + { nums }: { nums: number[] }, + context: any, + info: any, + ) => { + return nums.reduce((a, b) => a + b, 0); + }, + me: async (parent: any, args: any, context: any, info: any) => { + return { + id: 'jdillick', + name: 'John', + email: 'john@dillick.us', + }; + }, + + user: async (parent: any, { id }: any, context: any, info: any) => { + const user = await User.load(id); + return user; + }, + + users: async (parent: any, args: any, context: any, info: any) => { + // await new Promise((resolve) => setTimeout(resolve, 5000)); + const users = User.find(); + return users; + }, + + post: async ( + parent: any, + { id }: { id: number }, + context: any, + info: any, + ) => { + console.log({ id }); + return { + id: 123, + title: 'Hello World', + body: 'This is a post.', + published: true, + }; + }, + + posts: async (parent: any, { query }: any, context: any, info: any) => { + if (query) { + return Post.find({ title: { $regex: query, $options: 'i' } }); + } + return Post.find(); + }, }, - grades: async (parent: any, args: any, context: any, info: any) => { - return [1, 2, 3, 4, 5]; + Mutation: { + createUser: async ( + parent: any, + { name, email, age }: { name: string; email: string; age?: number }, + context: any, + info: any, + ) => { + const user = new User({ name, email, age }); + await user.save(); + return user; + }, + deleteUser: async ( + parent: any, + { id }: { id: string }, + context: any, + info: any, + ) => { + try { + const user = await User.delete(id); + return { success: true }; + } catch (e) { + return { success: false, message: e.message }; + } + }, + createPost: async ( + parent: any, + { + title, + body, + published, + }: { + title: string; + body: string; + published: boolean; + }, + context: any, + info: any, + ) => { + const post = new Post({ title, body, published }); + await post.save(); + return post; + }, }, - add: async ( - parent: any, - { nums }: { nums: number[] }, - context: any, - info: any - ) => { - return nums.reduce((a, b) => a + b, 0); - }, - me: async (parent: any, args: any, context: any, info: any) => { - return { - id: 'jdillick', - name: 'John', - email: 'john@dillick.us', - }; - }, - - user: async (parent: any, { id }: any, context: any, info: any) => { - const user = await User.load(id); - return user; - }, - - users: async (parent: any, args: any, context: any, info: any) => { - // await new Promise((resolve) => setTimeout(resolve, 5000)); - const users = User.find(); - return users; - }, - - post: async ( - parent: any, - { id }: { id: number }, - context: any, - info: any - ) => { - console.log({ id }); - return { - id: 123, - title: 'Hello World', - body: 'This is a post.', - published: true, - }; - }, - - posts: async (parent: any, { query }: any, context: any, info: any) => { - if (query) { - return Post.find({ title: { $regex: query, $options: 'i' } }); - } - return Post.find(); - }, - }, - Mutation: { - createUser: async ( - parent: any, - { name, email, age }: { name: string; email: string; age?: number }, - context: any, - info: any - ) => { - const user = new User({ name, email, age }); - await user.save(); - return user; - }, - deleteUser: async ( - parent: any, - { id }: { id: string }, - context: any, - info: any - ) => { - try { - const user = await User.delete(id); - return { success: true }; - } catch (e) { - return { success: false, message: e.message }; - } - }, - createPost: async ( - parent: any, - { - title, - body, - published, - }: { - title: string; - body: string; - published: boolean; - }, - context: any, - info: any - ) => { - const post = new Post({ title, body, published }); - await post.save(); - return post; - }, - }, }; const GraphQLService = await applyGraphQL({ - Router, - typeDefs, - resolvers, - context: (ctx) => { - // this line is for passing a user context for the auth - return { user: 'Boo' }; - }, + Router, + typeDefs, + resolvers, + context: (ctx) => { + // this line is for passing a user context for the auth + return { user: 'Boo' }; + }, }); app.use(GraphQLService.routes(), GraphQLService.allowedMethods()); diff --git a/reactium_modules/@reactium/graphql/reactium-boot.cjs b/reactium_modules/@reactium/graphql/reactium-boot.cjs index 4ef3e4e..9a7a864 100644 --- a/reactium_modules/@reactium/graphql/reactium-boot.cjs +++ b/reactium_modules/@reactium/graphql/reactium-boot.cjs @@ -9,13 +9,13 @@ const playgroundEnabled = process.env.NODE_ENV === 'development'; const proxyEnabled = process.env.GRAPHQL_PROXY_ENABLED !== 'off'; const graphqlAPI = - process.env.GRAPHQL_URL || `http://127.0.0.1:4000${graphqlProxyPath}`; + process.env.GRAPHQL_URL || `http://localhost:4000${graphqlProxyPath}`; const logLevel = process.env.DEBUG === 'on' ? 'debug' : 'error'; BOOT('GraphQL Module for Reactium...'); BOOT('GraphQL API:', graphqlAPI); DEBUG( - 'Set GraphQL API URL with GRAPHQL_URL environment variable (defaults to http://127.0.0.1:4000/graphql)', + 'Set GraphQL API URL with GRAPHQL_URL environment variable (defaults to http://localhost:4000/graphql)', ); BOOT('GraphQL Proxy:', proxyEnabled ? graphqlProxyPath : 'disabled'); diff --git a/src/app/components/Dashboard/Dashboard.jsx b/src/app/components/Dashboard/Dashboard.jsx index 93cfb16..1bd91c2 100644 --- a/src/app/components/Dashboard/Dashboard.jsx +++ b/src/app/components/Dashboard/Dashboard.jsx @@ -2,34 +2,70 @@ import { gql } from '@apollo/client'; import Container from 'react-bootstrap/Container'; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; -import { useHookComponent } from 'reactium-core/sdk'; +import { useHookComponent, useHandle } from 'reactium-core/sdk'; import { useSyncQuery } from '@reactium/graphql'; - -const LOAD_DASHBOARD_DATA = gql` - query LoadDashboardDat($nums: [Int!]!) { - users { - id - name - email - } - - posts { - id - title - body - } - - add(nums: $nums) - } -`; +import * as DeleteUser from './User/DeleteUser/DeleteUser'; export const Dashboard = () => { const PostList = useHookComponent('PostList'); const UserList = useHookComponent('UserList'); + const handle = useSyncQuery( + gql` + query LoadDashboardDat($nums: [Int!]!) { + users { + id + name + email + } + + posts { + id + title + body + } - const handle = useSyncQuery(LOAD_DASHBOARD_DATA, { - variables: { nums: [0, 1] }, - }); + add(nums: $nums) + } + `, + { + variables: { nums: [0, 1] }, + }, + ); + + const Modal = useHandle('Modal'); + const confirmDelete = (user) => { + Modal.set( + { + header: , + body: , + footer: ( + Modal.close()} + onSuccess={async () => { + const client = handle.get('client'); + await client.mutate({ + mutation: gql` + mutation DeleteUser($id: ID!) { + deleteUser(id: $id) { + success + message + } + } + `, + variables: { id: user.id }, + }); + + Modal.close(); + await handle.refresh(); + }} + /> + ), + }, + false, + ); + Modal.open(); + }; return ( @@ -40,6 +76,7 @@ export const Dashboard = () => { loading={handle.get('loading', false)} error={handle.get('error')} users={handle.get('data.users', [])} + onDelete={confirmDelete} /> diff --git a/src/app/components/Dashboard/User/DeleteUser/DeleteUser.jsx b/src/app/components/Dashboard/User/DeleteUser/DeleteUser.jsx new file mode 100644 index 0000000..5425c37 --- /dev/null +++ b/src/app/components/Dashboard/User/DeleteUser/DeleteUser.jsx @@ -0,0 +1,29 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button'; + +export const Header = ({ user }) => { + const { id, name } = user; + return

Delete {name}

; +}; + +export const Body = ({ user }) => { + return

Are you sure you want to delete {user.name}?

; +}; + +export const Footer = ({ + user, + onCancel = () => console.log('Cancel delete'), + onSuccess = (user) => console.log(`Delete user ${user.id}`), +}) => { + const { id } = user; + return ( + <> + + + + ); +}; diff --git a/src/app/components/Dashboard/User/DeleteUser/_reactium-style-molecules-DeleteUser.scss b/src/app/components/Dashboard/User/DeleteUser/_reactium-style-molecules-DeleteUser.scss new file mode 100644 index 0000000..2b2a70a --- /dev/null +++ b/src/app/components/Dashboard/User/DeleteUser/_reactium-style-molecules-DeleteUser.scss @@ -0,0 +1,3 @@ +.deleteuser { + +} diff --git a/src/app/components/Dashboard/User/DeleteUser/reactium-domain-deleteuser.js b/src/app/components/Dashboard/User/DeleteUser/reactium-domain-deleteuser.js new file mode 100644 index 0000000..2530d2d --- /dev/null +++ b/src/app/components/Dashboard/User/DeleteUser/reactium-domain-deleteuser.js @@ -0,0 +1,9 @@ +/** + * ----------------------------------------------------------------------------- + * DDD Domain DeleteUser - Change name to place domain artifacts in this directory + * in a different domain. + * ----------------------------------------------------------------------------- + */ +module.exports = { + name: 'DeleteUser', +}; diff --git a/src/app/components/GlobalModal/GlobalModal.jsx b/src/app/components/GlobalModal/GlobalModal.jsx index 370f635..52ffa22 100644 --- a/src/app/components/GlobalModal/GlobalModal.jsx +++ b/src/app/components/GlobalModal/GlobalModal.jsx @@ -1,8 +1,5 @@ import Modal from 'react-bootstrap/Modal'; -import { - cxFactory, - useRegisterSyncHandle, -} from '@atomic-reactor/reactium-core/sdk'; +import { cxFactory, useSyncHandle } from '@atomic-reactor/reactium-core/sdk'; import cn from 'classnames'; /** @@ -11,18 +8,7 @@ import cn from 'classnames'; * ----------------------------------------------------------------------------- */ export const GlobalModal = () => { - const handle = useRegisterSyncHandle('Modal', { - show: false, - cx: cxFactory('modal'), - className: '', - dialogProps: {}, - header: 'Modal Header', - headerProps: { closeButton: true }, - body: 'Modal Body', - bodyProps: {}, - footer: 'Modal Footer', - footerProps: {}, - }); + const handle = useSyncHandle('Modal'); handle.extend('open', () => handle.set('show', true)); handle.extend('close', () => handle.set('show', false)); diff --git a/src/app/components/GlobalModal/reactium-hooks-globalmodal.js b/src/app/components/GlobalModal/reactium-hooks-globalmodal.js index 1eb1c09..27ecc1a 100644 --- a/src/app/components/GlobalModal/reactium-hooks-globalmodal.js +++ b/src/app/components/GlobalModal/reactium-hooks-globalmodal.js @@ -4,9 +4,25 @@ * ----------------------------------------------------------------------------- */ (async () => { - const { Hook, Enums, Component, Handle, ReactiumSyncState, cxFactory } = - await import('@atomic-reactor/reactium-core/sdk'); - + const { Component, ReactiumSyncState, Handle, cxFactory } = await import( + '@atomic-reactor/reactium-core/sdk' + ); const { GlobalModal } = await import('./GlobalModal'); + Component.register('GlobalModal', GlobalModal); + + Handle.register('Modal', { + current: new ReactiumSyncState({ + show: false, + cx: cxFactory('modal'), + className: '', + dialogProps: {}, + header: 'Modal Header', + headerProps: { closeButton: true }, + body: 'Modal Body', + bodyProps: {}, + footer: 'Modal Footer', + footerProps: {}, + }), + }); })();