From 5a252885ec89379d11df3863f5ef30b81c12979e Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Sat, 30 Nov 2024 20:11:56 -0300 Subject: [PATCH 01/12] BA-1832: organizations --- .../OrganizationCreateMutation.graphql.ts | 298 +++++ .../ProfileItemFragment.graphql.ts | 4 +- .../ProfilesListFragment.graphql.ts | 184 +++ .../ProfilesListQuery.graphql.ts | 224 +++- .../__generated__/UserProfileQuery.graphql.ts | 10 +- .../profilesListRefetchable.graphql.ts | 293 +++++ .../MessagesList/MessagesGroup/index.tsx | 1 + .../modules/messages/SendMessage/index.tsx | 2 +- .../AccountMenu/AccountPopover/index.tsx | 2 + .../AddProfileMenuItem/index.tsx | 36 +- .../AddProfileMenuItem/styled.tsx | 7 + .../AddProfileMenuItem/types.ts | 5 + .../ProfilePopover/AddProfileModal/index.tsx | 207 +++ .../ProfilePopover/CurrentProfile/index.tsx | 4 +- .../ProfilesList/ProfileMenuItem/index.tsx | 5 + .../ProfilesList/ProfileMenuItem/types.ts | 3 +- .../ProfilePopover/ProfilesList/index.tsx | 109 +- .../ProfilePopover/ProfilesList/types.ts | 3 + .../graphql/mutations/OrganizationCreate.ts | 54 + .../profiles/graphql/queries/ProfilesList.ts | 26 +- .../profiles/graphql/queries/UserProfile.ts | 1 + packages/components/package.json | 1 + packages/components/schema.graphql | 1123 +++++++++++++---- pnpm-lock.yaml | 3 + 24 files changed, 2252 insertions(+), 353 deletions(-) create mode 100644 packages/components/__generated__/OrganizationCreateMutation.graphql.ts create mode 100644 packages/components/__generated__/ProfilesListFragment.graphql.ts create mode 100644 packages/components/__generated__/profilesListRefetchable.graphql.ts create mode 100644 packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/styled.tsx create mode 100644 packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx create mode 100644 packages/components/modules/profiles/graphql/mutations/OrganizationCreate.ts diff --git a/packages/components/__generated__/OrganizationCreateMutation.graphql.ts b/packages/components/__generated__/OrganizationCreateMutation.graphql.ts new file mode 100644 index 00000000..a80402e9 --- /dev/null +++ b/packages/components/__generated__/OrganizationCreateMutation.graphql.ts @@ -0,0 +1,298 @@ +/** + * @generated SignedSource<<4aff4a7daa3c996f8ce7a66b522ca1bb>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ + +/* eslint-disable */ +// @ts-nocheck +import { ConcreteRequest, Mutation } from 'relay-runtime' +import { FragmentRefs } from 'relay-runtime' + +export type OrganizationCreateInput = { + clientMutationId?: string | null | undefined + name: string + urlPath?: string | null | undefined +} +export type OrganizationCreateMutation$variables = { + input: OrganizationCreateInput +} +export type OrganizationCreateMutation$data = { + readonly organizationCreate: + | { + readonly errors: + | ReadonlyArray< + | { + readonly field: string + readonly messages: ReadonlyArray + } + | null + | undefined + > + | null + | undefined + readonly organization: + | { + readonly node: + | { + readonly id: string + } + | null + | undefined + } + | null + | undefined + readonly profile: + | { + readonly node: + | { + readonly ' $fragmentSpreads': FragmentRefs<'ProfileItemFragment'> + } + | null + | undefined + } + | null + | undefined + } + | null + | undefined +} +export type OrganizationCreateMutation = { + response: OrganizationCreateMutation$data + variables: OrganizationCreateMutation$variables +} + +const node: ConcreteRequest = (function () { + var v0 = [ + { + defaultValue: null, + kind: 'LocalArgument', + name: 'input', + }, + ], + v1 = [ + { + kind: 'Variable', + name: 'input', + variableName: 'input', + }, + ], + v2 = { + alias: null, + args: null, + kind: 'ScalarField', + name: 'id', + storageKey: null, + }, + v3 = { + alias: null, + args: null, + concreteType: 'OrganizationEdge', + kind: 'LinkedField', + name: 'organization', + plural: false, + selections: [ + { + alias: null, + args: null, + concreteType: 'Organization', + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [v2 /*: any*/], + storageKey: null, + }, + ], + storageKey: null, + }, + v4 = { + alias: null, + args: null, + concreteType: 'ErrorType', + kind: 'LinkedField', + name: 'errors', + plural: true, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'field', + storageKey: null, + }, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'messages', + storageKey: null, + }, + ], + storageKey: null, + } + return { + fragment: { + argumentDefinitions: v0 /*: any*/, + kind: 'Fragment', + metadata: null, + name: 'OrganizationCreateMutation', + selections: [ + { + alias: null, + args: v1 /*: any*/, + concreteType: 'OrganizationCreatePayload', + kind: 'LinkedField', + name: 'organizationCreate', + plural: false, + selections: [ + v3 /*: any*/, + { + alias: null, + args: null, + concreteType: 'ProfileEdge', + kind: 'LinkedField', + name: 'profile', + plural: false, + selections: [ + { + alias: null, + args: null, + concreteType: 'Profile', + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + { + args: null, + kind: 'FragmentSpread', + name: 'ProfileItemFragment', + }, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + v4 /*: any*/, + ], + storageKey: null, + }, + ], + type: 'Mutation', + abstractKey: null, + }, + kind: 'Request', + operation: { + argumentDefinitions: v0 /*: any*/, + kind: 'Operation', + name: 'OrganizationCreateMutation', + selections: [ + { + alias: null, + args: v1 /*: any*/, + concreteType: 'OrganizationCreatePayload', + kind: 'LinkedField', + name: 'organizationCreate', + plural: false, + selections: [ + v3 /*: any*/, + { + alias: null, + args: null, + concreteType: 'ProfileEdge', + kind: 'LinkedField', + name: 'profile', + plural: false, + selections: [ + { + alias: null, + args: null, + concreteType: 'Profile', + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + v2 /*: any*/, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'name', + storageKey: null, + }, + { + alias: null, + args: [ + { + kind: 'Literal', + name: 'height', + value: 100, + }, + { + kind: 'Literal', + name: 'width', + value: 100, + }, + ], + concreteType: 'File', + kind: 'LinkedField', + name: 'image', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'url', + storageKey: null, + }, + ], + storageKey: 'image(height:100,width:100)', + }, + { + alias: null, + args: null, + concreteType: 'URLPath', + kind: 'LinkedField', + name: 'urlPath', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'path', + storageKey: null, + }, + v2 /*: any*/, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + v4 /*: any*/, + ], + storageKey: null, + }, + ], + }, + params: { + cacheID: '695d91d3d1771c63d98fd763396c8088', + id: null, + metadata: {}, + name: 'OrganizationCreateMutation', + operationKind: 'mutation', + text: 'mutation OrganizationCreateMutation(\n $input: OrganizationCreateInput!\n) {\n organizationCreate(input: $input) {\n organization {\n node {\n id\n }\n }\n profile {\n node {\n ...ProfileItemFragment\n id\n }\n }\n errors {\n field\n messages\n }\n }\n}\n\nfragment ProfileItemFragment on Profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n urlPath {\n path\n id\n }\n}\n', + }, + } +})() + +;(node as any).hash = '61fbf11e46dfbf921af0e82290abc5eb' + +export default node diff --git a/packages/components/__generated__/ProfileItemFragment.graphql.ts b/packages/components/__generated__/ProfileItemFragment.graphql.ts index 78be7cd9..13bb584c 100644 --- a/packages/components/__generated__/ProfileItemFragment.graphql.ts +++ b/packages/components/__generated__/ProfileItemFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<5654b1a588bbb091cce70cdee1e0ccff>> * @lightSyntaxTransform * @nogrep */ @@ -111,6 +111,6 @@ const node: ReaderFragment = { abstractKey: null, } -;(node as any).hash = 'b32115278ad65ec9a310b97d23b5c85b' +;(node as any).hash = 'cc90631aac89344f22ce8e98cab7d7e4' export default node diff --git a/packages/components/__generated__/ProfilesListFragment.graphql.ts b/packages/components/__generated__/ProfilesListFragment.graphql.ts new file mode 100644 index 00000000..3a70d8c7 --- /dev/null +++ b/packages/components/__generated__/ProfilesListFragment.graphql.ts @@ -0,0 +1,184 @@ +/** + * @generated SignedSource<<7d7b83632e53e7be35ccbbafa28ea310>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ + +/* eslint-disable */ +// @ts-nocheck +import { ReaderFragment, RefetchableFragment } from 'relay-runtime' +import { FragmentRefs } from 'relay-runtime' + +export type ProfilesListFragment$data = { + readonly id: string + readonly profiles: + | { + readonly edges: ReadonlyArray< + | { + readonly cursor: string + readonly node: + | { + readonly id: string + readonly ' $fragmentSpreads': FragmentRefs<'ProfileItemFragment'> + } + | null + | undefined + } + | null + | undefined + > + readonly pageInfo: { + readonly endCursor: string | null | undefined + readonly hasNextPage: boolean + } + } + | null + | undefined + readonly ' $fragmentType': 'ProfilesListFragment' +} +export type ProfilesListFragment$key = { + readonly ' $data'?: ProfilesListFragment$data + readonly ' $fragmentSpreads': FragmentRefs<'ProfilesListFragment'> +} + +const node: ReaderFragment = (function () { + var v0 = ['profiles'], + v1 = { + alias: null, + args: null, + kind: 'ScalarField', + name: 'id', + storageKey: null, + } + return { + argumentDefinitions: [ + { + defaultValue: 10, + kind: 'LocalArgument', + name: 'count', + }, + { + defaultValue: null, + kind: 'LocalArgument', + name: 'cursor', + }, + ], + kind: 'Fragment', + metadata: { + connection: [ + { + count: 'count', + cursor: 'cursor', + direction: 'forward', + path: v0 /*: any*/, + }, + ], + refetch: { + connection: { + forward: { + count: 'count', + cursor: 'cursor', + }, + backward: null, + path: v0 /*: any*/, + }, + fragmentPathInResult: ['node'], + operation: require('./profilesListRefetchable.graphql'), + identifierInfo: { + identifierField: 'id', + identifierQueryVariableName: 'id', + }, + }, + }, + name: 'ProfilesListFragment', + selections: [ + v1 /*: any*/, + { + alias: 'profiles', + args: null, + concreteType: 'ProfileConnection', + kind: 'LinkedField', + name: '__ProfilesListFragment_profiles_connection', + plural: false, + selections: [ + { + alias: null, + args: null, + concreteType: 'ProfileEdge', + kind: 'LinkedField', + name: 'edges', + plural: true, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'cursor', + storageKey: null, + }, + { + alias: null, + args: null, + concreteType: 'Profile', + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + v1 /*: any*/, + { + args: null, + kind: 'FragmentSpread', + name: 'ProfileItemFragment', + }, + { + alias: null, + args: null, + kind: 'ScalarField', + name: '__typename', + storageKey: null, + }, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + { + alias: null, + args: null, + concreteType: 'PageInfo', + kind: 'LinkedField', + name: 'pageInfo', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'hasNextPage', + storageKey: null, + }, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'endCursor', + storageKey: null, + }, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + ], + type: 'User', + abstractKey: null, + } +})() + +;(node as any).hash = '220e97b8d45724f507762ff4f3d39dce' + +export default node diff --git a/packages/components/__generated__/ProfilesListQuery.graphql.ts b/packages/components/__generated__/ProfilesListQuery.graphql.ts index de7779da..7ce825d5 100644 --- a/packages/components/__generated__/ProfilesListQuery.graphql.ts +++ b/packages/components/__generated__/ProfilesListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -11,20 +11,15 @@ import { ConcreteRequest, Query } from 'relay-runtime' import { FragmentRefs } from 'relay-runtime' -export type ProfilesListQuery$variables = Record +export type ProfilesListQuery$variables = { + count: number + cursor?: string | null | undefined +} export type ProfilesListQuery$data = { readonly me: | { - readonly profiles: - | ReadonlyArray< - | { - readonly ' $fragmentSpreads': FragmentRefs<'ProfileItemFragment'> - } - | null - | undefined - > - | null - | undefined + readonly id: string + readonly ' $fragmentSpreads': FragmentRefs<'ProfilesListFragment'> } | null | undefined @@ -35,16 +30,40 @@ export type ProfilesListQuery = { } const node: ConcreteRequest = (function () { - var v0 = { - alias: null, - args: null, - kind: 'ScalarField', - name: 'id', - storageKey: null, - } + var v0 = [ + { + defaultValue: null, + kind: 'LocalArgument', + name: 'count', + }, + { + defaultValue: null, + kind: 'LocalArgument', + name: 'cursor', + }, + ], + v1 = { + alias: null, + args: null, + kind: 'ScalarField', + name: 'id', + storageKey: null, + }, + v2 = [ + { + kind: 'Variable', + name: 'after', + variableName: 'cursor', + }, + { + kind: 'Variable', + name: 'first', + variableName: 'count', + }, + ] return { fragment: { - argumentDefinitions: [], + argumentDefinitions: v0 /*: any*/, kind: 'Fragment', metadata: null, name: 'ProfilesListQuery', @@ -57,21 +76,22 @@ const node: ConcreteRequest = (function () { name: 'me', plural: false, selections: [ + v1 /*: any*/, { - alias: null, - args: null, - concreteType: 'Profile', - kind: 'LinkedField', - name: 'profiles', - plural: true, - selections: [ + args: [ { - args: null, - kind: 'FragmentSpread', - name: 'ProfileItemFragment', + kind: 'Variable', + name: 'count', + variableName: 'count', + }, + { + kind: 'Variable', + name: 'cursor', + variableName: 'cursor', }, ], - storageKey: null, + kind: 'FragmentSpread', + name: 'ProfilesListFragment', }, ], storageKey: null, @@ -82,7 +102,7 @@ const node: ConcreteRequest = (function () { }, kind: 'Request', operation: { - argumentDefinitions: [], + argumentDefinitions: v0 /*: any*/, kind: 'Operation', name: 'ProfilesListQuery', selections: [ @@ -94,90 +114,160 @@ const node: ConcreteRequest = (function () { name: 'me', plural: false, selections: [ + v1 /*: any*/, { alias: null, - args: null, - concreteType: 'Profile', + args: v2 /*: any*/, + concreteType: 'ProfileConnection', kind: 'LinkedField', name: 'profiles', - plural: true, + plural: false, selections: [ - v0 /*: any*/, { alias: null, args: null, - kind: 'ScalarField', - name: 'name', - storageKey: null, - }, - { - alias: null, - args: [ - { - kind: 'Literal', - name: 'height', - value: 100, - }, - { - kind: 'Literal', - name: 'width', - value: 100, - }, - ], - concreteType: 'File', + concreteType: 'ProfileEdge', kind: 'LinkedField', - name: 'image', - plural: false, + name: 'edges', + plural: true, selections: [ { alias: null, args: null, kind: 'ScalarField', - name: 'url', + name: 'cursor', + storageKey: null, + }, + { + alias: null, + args: null, + concreteType: 'Profile', + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + v1 /*: any*/, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'name', + storageKey: null, + }, + { + alias: null, + args: [ + { + kind: 'Literal', + name: 'height', + value: 100, + }, + { + kind: 'Literal', + name: 'width', + value: 100, + }, + ], + concreteType: 'File', + kind: 'LinkedField', + name: 'image', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'url', + storageKey: null, + }, + ], + storageKey: 'image(height:100,width:100)', + }, + { + alias: null, + args: null, + concreteType: 'URLPath', + kind: 'LinkedField', + name: 'urlPath', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'path', + storageKey: null, + }, + v1 /*: any*/, + ], + storageKey: null, + }, + { + alias: null, + args: null, + kind: 'ScalarField', + name: '__typename', + storageKey: null, + }, + ], storageKey: null, }, ], - storageKey: 'image(height:100,width:100)', + storageKey: null, }, { alias: null, args: null, - concreteType: 'URLPath', + concreteType: 'PageInfo', kind: 'LinkedField', - name: 'urlPath', + name: 'pageInfo', plural: false, selections: [ { alias: null, args: null, kind: 'ScalarField', - name: 'path', + name: 'hasNextPage', + storageKey: null, + }, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'endCursor', storageKey: null, }, - v0 /*: any*/, ], storageKey: null, }, ], storageKey: null, }, - v0 /*: any*/, + { + alias: null, + args: v2 /*: any*/, + filters: null, + handle: 'connection', + key: 'ProfilesListFragment_profiles', + kind: 'LinkedHandle', + name: 'profiles', + }, ], storageKey: null, }, ], }, params: { - cacheID: 'f45449b4beffd5247f8dd3fcb75e43cd', + cacheID: '4254a9462b2759817c71e9febce50ff8', id: null, metadata: {}, name: 'ProfilesListQuery', operationKind: 'query', - text: 'query ProfilesListQuery {\n me {\n profiles {\n ...ProfileItemFragment\n id\n }\n id\n }\n}\n\nfragment ProfileItemFragment on Profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n urlPath {\n path\n id\n }\n}\n', + text: 'query ProfilesListQuery(\n $count: Int!\n $cursor: String\n) {\n me {\n id\n ...ProfilesListFragment_1G22uz\n }\n}\n\nfragment ProfileItemFragment on Profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n urlPath {\n path\n id\n }\n}\n\nfragment ProfilesListFragment_1G22uz on User {\n id\n profiles(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...ProfileItemFragment\n __typename\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n', }, } })() -;(node as any).hash = 'ce9ca315be07ccdb58629abb177bc931' +;(node as any).hash = 'f29be79e4f4e86911f0532d2c86db263' export default node diff --git a/packages/components/__generated__/UserProfileQuery.graphql.ts b/packages/components/__generated__/UserProfileQuery.graphql.ts index 4029d1fe..4fb2e338 100644 --- a/packages/components/__generated__/UserProfileQuery.graphql.ts +++ b/packages/components/__generated__/UserProfileQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<6a78928961965b4807c4cd830f7dd703>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -17,6 +17,7 @@ export type UserProfileQuery$data = { | { readonly profile: | { + readonly id: string readonly ' $fragmentSpreads': FragmentRefs<'ProfileItemFragment'> } | null @@ -61,6 +62,7 @@ const node: ConcreteRequest = (function () { name: 'profile', plural: false, selections: [ + v0 /*: any*/, { args: null, kind: 'FragmentSpread', @@ -164,16 +166,16 @@ const node: ConcreteRequest = (function () { ], }, params: { - cacheID: '4a09b56bb39794e18b189981877fa031', + cacheID: 'bf91f0acfc2126f408b4cbe09838bbda', id: null, metadata: {}, name: 'UserProfileQuery', operationKind: 'query', - text: 'query UserProfileQuery {\n me {\n profile {\n ...ProfileItemFragment\n id\n }\n id\n }\n}\n\nfragment ProfileItemFragment on Profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n urlPath {\n path\n id\n }\n}\n', + text: 'query UserProfileQuery {\n me {\n profile {\n id\n ...ProfileItemFragment\n }\n id\n }\n}\n\nfragment ProfileItemFragment on Profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n urlPath {\n path\n id\n }\n}\n', }, } })() -;(node as any).hash = '8febc9fbb812c3456d12d0ff6a69c90a' +;(node as any).hash = '66224b5e2a7b852c882a5c0b76571987' export default node diff --git a/packages/components/__generated__/profilesListRefetchable.graphql.ts b/packages/components/__generated__/profilesListRefetchable.graphql.ts new file mode 100644 index 00000000..ba0b3a3a --- /dev/null +++ b/packages/components/__generated__/profilesListRefetchable.graphql.ts @@ -0,0 +1,293 @@ +/** + * @generated SignedSource<<9122eddc8565511648fff888985f63a5>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ + +/* eslint-disable */ +// @ts-nocheck +import { ConcreteRequest, Query } from 'relay-runtime' +import { FragmentRefs } from 'relay-runtime' + +export type profilesListRefetchable$variables = { + count?: number | null | undefined + cursor?: string | null | undefined + id: string +} +export type profilesListRefetchable$data = { + readonly node: + | { + readonly ' $fragmentSpreads': FragmentRefs<'ProfilesListFragment'> + } + | null + | undefined +} +export type profilesListRefetchable = { + response: profilesListRefetchable$data + variables: profilesListRefetchable$variables +} + +const node: ConcreteRequest = (function () { + var v0 = [ + { + defaultValue: 10, + kind: 'LocalArgument', + name: 'count', + }, + { + defaultValue: null, + kind: 'LocalArgument', + name: 'cursor', + }, + { + defaultValue: null, + kind: 'LocalArgument', + name: 'id', + }, + ], + v1 = [ + { + kind: 'Variable', + name: 'id', + variableName: 'id', + }, + ], + v2 = { + alias: null, + args: null, + kind: 'ScalarField', + name: '__typename', + storageKey: null, + }, + v3 = { + alias: null, + args: null, + kind: 'ScalarField', + name: 'id', + storageKey: null, + }, + v4 = [ + { + kind: 'Variable', + name: 'after', + variableName: 'cursor', + }, + { + kind: 'Variable', + name: 'first', + variableName: 'count', + }, + ] + return { + fragment: { + argumentDefinitions: v0 /*: any*/, + kind: 'Fragment', + metadata: null, + name: 'profilesListRefetchable', + selections: [ + { + alias: null, + args: v1 /*: any*/, + concreteType: null, + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + { + args: [ + { + kind: 'Variable', + name: 'count', + variableName: 'count', + }, + { + kind: 'Variable', + name: 'cursor', + variableName: 'cursor', + }, + ], + kind: 'FragmentSpread', + name: 'ProfilesListFragment', + }, + ], + storageKey: null, + }, + ], + type: 'Query', + abstractKey: null, + }, + kind: 'Request', + operation: { + argumentDefinitions: v0 /*: any*/, + kind: 'Operation', + name: 'profilesListRefetchable', + selections: [ + { + alias: null, + args: v1 /*: any*/, + concreteType: null, + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + v2 /*: any*/, + v3 /*: any*/, + { + kind: 'InlineFragment', + selections: [ + { + alias: null, + args: v4 /*: any*/, + concreteType: 'ProfileConnection', + kind: 'LinkedField', + name: 'profiles', + plural: false, + selections: [ + { + alias: null, + args: null, + concreteType: 'ProfileEdge', + kind: 'LinkedField', + name: 'edges', + plural: true, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'cursor', + storageKey: null, + }, + { + alias: null, + args: null, + concreteType: 'Profile', + kind: 'LinkedField', + name: 'node', + plural: false, + selections: [ + v3 /*: any*/, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'name', + storageKey: null, + }, + { + alias: null, + args: [ + { + kind: 'Literal', + name: 'height', + value: 100, + }, + { + kind: 'Literal', + name: 'width', + value: 100, + }, + ], + concreteType: 'File', + kind: 'LinkedField', + name: 'image', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'url', + storageKey: null, + }, + ], + storageKey: 'image(height:100,width:100)', + }, + { + alias: null, + args: null, + concreteType: 'URLPath', + kind: 'LinkedField', + name: 'urlPath', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'path', + storageKey: null, + }, + v3 /*: any*/, + ], + storageKey: null, + }, + v2 /*: any*/, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + { + alias: null, + args: null, + concreteType: 'PageInfo', + kind: 'LinkedField', + name: 'pageInfo', + plural: false, + selections: [ + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'hasNextPage', + storageKey: null, + }, + { + alias: null, + args: null, + kind: 'ScalarField', + name: 'endCursor', + storageKey: null, + }, + ], + storageKey: null, + }, + ], + storageKey: null, + }, + { + alias: null, + args: v4 /*: any*/, + filters: null, + handle: 'connection', + key: 'ProfilesListFragment_profiles', + kind: 'LinkedHandle', + name: 'profiles', + }, + ], + type: 'User', + abstractKey: null, + }, + ], + storageKey: null, + }, + ], + }, + params: { + cacheID: '4076e2b1f754ffe0e086cd58c1941149', + id: null, + metadata: {}, + name: 'profilesListRefetchable', + operationKind: 'query', + text: 'query profilesListRefetchable(\n $count: Int = 10\n $cursor: String\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProfilesListFragment_1G22uz\n id\n }\n}\n\nfragment ProfileItemFragment on Profile {\n id\n name\n image(width: 100, height: 100) {\n url\n }\n urlPath {\n path\n id\n }\n}\n\nfragment ProfilesListFragment_1G22uz on User {\n id\n profiles(first: $count, after: $cursor) {\n edges {\n cursor\n node {\n id\n ...ProfileItemFragment\n __typename\n }\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n', + }, + } +})() + +;(node as any).hash = '220e97b8d45724f507762ff4f3d39dce' + +export default node diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx index 2705444c..369e9dae 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx @@ -6,6 +6,7 @@ import { datesDontHaveSameDay } from '@baseapp-frontend/utils' import { Box, Divider, Typography, useTheme } from '@mui/material' import { DateTime } from 'luxon' +import { useFragment } from 'react-relay' import { MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME, diff --git a/packages/components/modules/messages/SendMessage/index.tsx b/packages/components/modules/messages/SendMessage/index.tsx index 00ff308f..0c325880 100644 --- a/packages/components/modules/messages/SendMessage/index.tsx +++ b/packages/components/modules/messages/SendMessage/index.tsx @@ -7,7 +7,7 @@ import { setFormRelayErrors } from '@baseapp-frontend/utils' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' -import { ConnectionHandler } from 'react-relay' +import { ConnectionHandler, useFragment } from 'react-relay' import DefaultSocialInput from '../../__shared__/SocialInput' import { diff --git a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx index 86aefb45..c7690039 100644 --- a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx +++ b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx @@ -6,6 +6,7 @@ import { useCurrentProfile } from '@baseapp-frontend/authentication' import { ClickableAvatar, Popover, usePopover } from '@baseapp-frontend/design-system' import Divider from '@mui/material/Divider' +import { useFragment } from 'react-relay' import { AddProfileMenuItem as DefaultAddProfileMenuItem, @@ -13,6 +14,7 @@ import { ProfilesList as DefaultProfilesList, SwitchProfileMenu as DefaultSwitchProfileMenu, } from '../../../../profiles' +import { ProfileItemFragment } from '../../../../profiles/graphql/queries/ProfileItem' import DefaultCurrentUser from './CurrentUser' import LogoutItem from './LogoutItem' import DefaultMenuItems from './MenuItems' diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/index.tsx b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/index.tsx index 2b00ea3e..f21f0aca 100644 --- a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/index.tsx @@ -1,20 +1,36 @@ -import { FC } from 'react' +'use client' + +import { FC, useState } from 'react' import { AddIcon } from '@baseapp-frontend/design-system' import { ButtonBase, MenuItem, Stack } from '@mui/material' +import AddProfileModal from '../AddProfileModal' import { AddProfileMenuItemProps } from './types' const AddProfileMenuItem: FC = ({ - addNewProfileLabel = 'New profile', -}) => ( - - - {addNewProfileLabel} - - - -) + addNewProfileLabel = 'New organization', + CreateProfileModal = AddProfileModal, +}) => { + const [open, setOpen] = useState(false) + + return ( + <> + + setOpen(true)} + > + {addNewProfileLabel} + + + + + + ) +} export default AddProfileMenuItem diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/styled.tsx b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/styled.tsx new file mode 100644 index 00000000..da7a8161 --- /dev/null +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/styled.tsx @@ -0,0 +1,7 @@ +import { styled } from '@mui/material' + +export const Form = styled('form')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(2), +})) diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts index 8e16e3b1..5d43a747 100644 --- a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts @@ -1,3 +1,8 @@ +import { FC } from 'react' + +import { AddProfileModalProps } from '../AddProfileModal' + export interface AddProfileMenuItemProps { addNewProfileLabel?: string + CreateProfileModal?: FC } diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx new file mode 100644 index 00000000..71cdb6d5 --- /dev/null +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx @@ -0,0 +1,207 @@ +import { FC } from 'react' + +import { TextField } from '@baseapp-frontend/design-system' +import { setFormRelayErrors } from '@baseapp-frontend/utils' + +import { zodResolver } from '@hookform/resolvers/zod' +import { LoadingButton } from '@mui/lab' +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Link, + Typography, +} from '@mui/material' +import { useForm } from 'react-hook-form' +import { ConnectionHandler } from 'react-relay' +import slugify from 'slugify' +import z from 'zod' + +import { Form } from '../../../__shared__/SocialInput/styled' +import { useOrganizationCreateMutation } from '../../graphql/mutations/OrganizationCreate' + +const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/ + +const schema = z.object({ + name: z + .string() + .trim() + .min(3, { message: 'Must have at least three character' }) + .max(255, { message: 'Must have at most 255 characters' }), + urlPath: z + .string() + .regex(slugRegex, 'Must contain only lowercase letters, numbers, and hyphens') + .max(500, { message: 'Must have at most 500 characters' }), +}) + +let nextClientMutationId = 0 + +export interface AddProfileModalProps { + addNewProfileLabel?: string + termsAndConditionsUrl?: string + addNewProfileDescription?: string + onClose?: () => void + open: boolean + setOpen: (open: boolean) => void + submitLabel?: string +} + +interface OrganizationCreateForm { + name: string + urlPath: string +} + +const AddProfileModal: FC = ({ + addNewProfileLabel = 'New organization', + termsAndConditionsUrl = '', + addNewProfileDescription = 'Create an organization and invite multiple members to manage and collaborate.', + submitLabel = 'Create Organization', + onClose, + open, + setOpen, +}) => { + const form = useForm({ + defaultValues: { + name: '', + urlPath: '', + }, + resolver: zodResolver(schema), + }) + + const [commitMutation, isMutationInFlight] = useOrganizationCreateMutation() + + const handleClose = () => { + setOpen(false) + form.reset() + onClose?.() + } + + const onSubmit = (data: OrganizationCreateForm) => { + if (isMutationInFlight) return + + nextClientMutationId += 1 + const clientMutationId = nextClientMutationId.toString() + + commitMutation({ + variables: { + input: { + name: data.name, + urlPath: data.urlPath, + clientMutationId, + }, + }, + updater: (store) => { + const payload = store.getRootField('organizationCreate') + if (!payload) { + return + } + + const newEdge = payload.getLinkedRecord('profile') + + const root = store.getRoot() + const meRecord = root?.getLinkedRecord('me') + + if (!meRecord) { + console.error('Unable to find `me` record in the store') + return + } + + const connection = ConnectionHandler.getConnection( + meRecord, + 'ProfilesListFragment_profiles', + ) + + if (!connection) { + console.error('Unable to find connection `ProfilesListFragment_profiles` in the store') + return + } + + ConnectionHandler.insertEdgeBefore(connection, newEdge) + }, + onCompleted: (response, errors) => { + if (errors) { + console.error(errors) + return + } + const mutationErrors = response?.organizationCreate?.errors + setFormRelayErrors(form, mutationErrors) + + if (!mutationErrors?.length) { + handleClose() + } + }, + onError: console.error, + }) + } + + return ( + + {addNewProfileLabel} +
+ + {addNewProfileDescription} + { + form.trigger('name') + }} + onBlur={() => { + if (!form.getValues('urlPath')) { + form.setValue('urlPath', slugify(form.getValues('name').toLocaleLowerCase())) + form.trigger('urlPath') + } + }} + /> + { + form.trigger('urlPath') + }} + /> + + Upon confirming, you agree to our{' '} + + Terms and Conditions. + + + + + + 0} + > + {submitLabel} + + +
+
+ ) +} + +export default AddProfileModal diff --git a/packages/components/modules/profiles/ProfilePopover/CurrentProfile/index.tsx b/packages/components/modules/profiles/ProfilePopover/CurrentProfile/index.tsx index a7d44f44..ae1efb8e 100644 --- a/packages/components/modules/profiles/ProfilePopover/CurrentProfile/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/CurrentProfile/index.tsx @@ -15,7 +15,7 @@ const CurrentProfile: FC = () => { @@ -24,7 +24,7 @@ const CurrentProfile: FC = () => { {profile.name} - {profile.urlPath && ( + {profile?.urlPath && ( {profile.urlPath} diff --git a/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/index.tsx b/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/index.tsx index 4b84f49c..acf0bf2e 100644 --- a/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/index.tsx @@ -20,7 +20,12 @@ const ProfileMenuItem: FC = ({ const { currentProfile } = useCurrentProfile() const profile = useFragment(ProfileItemFragment, profileRef) + if (!profile) { + return null // Safeguard for invalid fragment reference + } + const profileUrlPath = profile.urlPath?.path + const isActiveProfile = profile.id === currentProfile?.id return ( diff --git a/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/types.ts b/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/types.ts index 92b6a5cf..d865e862 100644 --- a/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/types.ts +++ b/packages/components/modules/profiles/ProfilePopover/ProfilesList/ProfileMenuItem/types.ts @@ -2,7 +2,7 @@ import type { AvatarWithPlaceholderProps } from '@baseapp-frontend/design-system import { type MenuItemProps } from '@mui/material' -import type { +import { ProfileItemFragment$data, ProfileItemFragment$key, } from '../../../../../__generated__/ProfileItemFragment.graphql' @@ -10,6 +10,7 @@ import type { export interface ProfileMenuItemProps { profileRef: ProfileItemFragment$key onProfileChange: (newProfile: ProfileItemFragment$data) => void + currentProfile?: ProfileItemFragment$key avatarProps?: AvatarWithPlaceholderProps width?: number height?: number diff --git a/packages/components/modules/profiles/ProfilePopover/ProfilesList/index.tsx b/packages/components/modules/profiles/ProfilePopover/ProfilesList/index.tsx index 5151c6bf..37f4ad3b 100644 --- a/packages/components/modules/profiles/ProfilePopover/ProfilesList/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/ProfilesList/index.tsx @@ -1,24 +1,39 @@ 'use client' -import { FC, Suspense } from 'react' +import { FC, Suspense, useMemo } from 'react' import { useCurrentProfile } from '@baseapp-frontend/authentication' import { ChevronIcon } from '@baseapp-frontend/design-system' import { useNotification } from '@baseapp-frontend/utils' import { Box, ButtonBase, Divider, Slide } from '@mui/material' -import { useLazyLoadQuery } from 'react-relay' +import { useLazyLoadQuery, usePaginationFragment } from 'react-relay' +import { Virtuoso } from 'react-virtuoso' -import { ProfileItemFragment$data } from '../../../../__generated__/ProfileItemFragment.graphql' +import { + ProfileItemFragment$data, + ProfileItemFragment$key, +} from '../../../../__generated__/ProfileItemFragment.graphql' +import { ProfilesListFragment$key } from '../../../../__generated__/ProfilesListFragment.graphql' import { ProfilesListQuery as ProfilesListQueryType } from '../../../../__generated__/ProfilesListQuery.graphql' -import { ProfilesListQuery } from '../../graphql/queries/ProfilesList' +import EmptyState from '../../../notifications/NotificationsList/EmptyState' +import { ProfilesListFragment, ProfilesListQuery } from '../../graphql/queries/ProfilesList' import LoadingState from './LoadingState' import ProfileMenuItem from './ProfileMenuItem' import { CancelMenuItem, StyledList } from './styled' import { ProfilesListProps } from './types' -const ProfilesList: FC = ({ handleCloseSubmenu, MenuItemProps }) => { - const { me } = useLazyLoadQuery(ProfilesListQuery, {}) +const ProfilesList: FC = ({ + handleCloseSubmenu, + MenuItemProps, + LoadingStateProps = {}, + listMaxHeight = 300, +}) => { + const options = { count: 10 } + const { me } = useLazyLoadQuery(ProfilesListQuery, options, { + fetchPolicy: 'store-and-network', + }) + const { sendToast } = useNotification() const { currentProfile, setCurrentProfile } = useCurrentProfile() @@ -39,21 +54,79 @@ const ProfilesList: FC = ({ handleCloseSubmenu, MenuItemProps } } - return me?.profiles?.map((profileRef, index) => { - if (!profileRef) return null + const { data, loadNext, isLoadingNext, hasNext } = usePaginationFragment< + ProfilesListQueryType, + ProfilesListFragment$key + >(ProfilesListFragment, me) + + const profiles = useMemo( + () => data?.profiles?.edges.filter((edge) => edge?.node).map((edge) => edge?.node) || [], + [data?.profiles?.edges], + ) + + const renderVirtuosoLoadingState = () => { + if (!isLoadingNext) return + + return ( + + ) + } + + const renderProfileItem = ( + profile: ProfileItemFragment$key | null | undefined, + index: number, + ) => { + if (!profile) return null + return ( ) - }) + } + + const renderContent = () => { + if (profiles.length === 0) return + + const minHeight = profiles.length * 56 > listMaxHeight ? listMaxHeight : profiles.length * 56 + + return ( + + renderProfileItem(profile, index)} + components={{ + Footer: renderVirtuosoLoadingState, + }} + endReached={() => { + if (hasNext) { + loadNext(10) + } + }} + /> + + ) + } + + return ( + + + {renderContent()} + + + ) } const ProfilesListSuspended: FC = (props) => { - const { openSubmenu, handleCloseSubmenu, cancelLabel = 'Cancel', listMaxHeight = 300 } = props + const { openSubmenu, handleCloseSubmenu, cancelLabel = 'Cancel' } = props return ( @@ -66,15 +139,9 @@ const ProfilesListSuspended: FC = (props) => { - - }> - - - + }> + + diff --git a/packages/components/modules/profiles/ProfilePopover/ProfilesList/types.ts b/packages/components/modules/profiles/ProfilePopover/ProfilesList/types.ts index 0987f033..2e8c1e38 100644 --- a/packages/components/modules/profiles/ProfilePopover/ProfilesList/types.ts +++ b/packages/components/modules/profiles/ProfilePopover/ProfilesList/types.ts @@ -1,3 +1,5 @@ +import { LoadingStateProps } from '@baseapp-frontend/design-system/components/displays/LoadingState/types' + import type { ProfileMenuItemProps } from './ProfileMenuItem/types' export interface ProfilesListProps { @@ -6,4 +8,5 @@ export interface ProfilesListProps { cancelLabel?: string listMaxHeight?: number MenuItemProps?: Partial + LoadingStateProps?: LoadingStateProps } diff --git a/packages/components/modules/profiles/graphql/mutations/OrganizationCreate.ts b/packages/components/modules/profiles/graphql/mutations/OrganizationCreate.ts new file mode 100644 index 00000000..39fd16cb --- /dev/null +++ b/packages/components/modules/profiles/graphql/mutations/OrganizationCreate.ts @@ -0,0 +1,54 @@ +import { useNotification } from '@baseapp-frontend/utils' + +import { Disposable, UseMutationConfig, graphql, useMutation } from 'react-relay' + +import { OrganizationCreateMutation } from '../../../../__generated__/OrganizationCreateMutation.graphql' + +export const OrganizationCreateMutationQuery = graphql` + mutation OrganizationCreateMutation($input: OrganizationCreateInput!) { + organizationCreate(input: $input) { + organization { + node { + id + } + } + profile { + node { + ...ProfileItemFragment + } + } + errors { + field + messages + } + } + } +` + +export const useOrganizationCreateMutation = (): [ + (config: UseMutationConfig) => Disposable, + boolean, +] => { + const { sendToast } = useNotification() + const [commitMutation, isMutationInFlight] = useMutation( + OrganizationCreateMutationQuery, + ) + + const commit = (config: UseMutationConfig) => + commitMutation({ + ...config, + + onCompleted: (response, errors) => { + errors?.forEach((error) => { + sendToast(error.message, { type: 'error' }) + }) + config?.onCompleted?.(response, errors) + }, + onError: (error) => { + sendToast(error.message, { type: 'error' }) + config?.onError?.(error) + }, + }) + + return [commit, isMutationInFlight] +} diff --git a/packages/components/modules/profiles/graphql/queries/ProfilesList.ts b/packages/components/modules/profiles/graphql/queries/ProfilesList.ts index 23a9e46d..3490e0a1 100644 --- a/packages/components/modules/profiles/graphql/queries/ProfilesList.ts +++ b/packages/components/modules/profiles/graphql/queries/ProfilesList.ts @@ -1,10 +1,30 @@ import { graphql } from 'react-relay' export const ProfilesListQuery = graphql` - query ProfilesListQuery { + query ProfilesListQuery($count: Int!, $cursor: String) { me { - profiles { - ...ProfileItemFragment + id + ...ProfilesListFragment @arguments(count: $count, cursor: $cursor) + } + } +` + +export const ProfilesListFragment = graphql` + fragment ProfilesListFragment on User + @argumentDefinitions(count: { type: "Int", defaultValue: 10 }, cursor: { type: "String" }) + @refetchable(queryName: "profilesListRefetchable") { + id + profiles(first: $count, after: $cursor) @connection(key: "ProfilesListFragment_profiles") { + edges { + cursor + node { + id + ...ProfileItemFragment + } + } + pageInfo { + hasNextPage + endCursor } } } diff --git a/packages/components/modules/profiles/graphql/queries/UserProfile.ts b/packages/components/modules/profiles/graphql/queries/UserProfile.ts index 92d0cf23..476be307 100644 --- a/packages/components/modules/profiles/graphql/queries/UserProfile.ts +++ b/packages/components/modules/profiles/graphql/queries/UserProfile.ts @@ -5,6 +5,7 @@ export const UserProfileQuery = graphql` query UserProfileQuery { me { profile { + id ...ProfileItemFragment } } diff --git a/packages/components/package.json b/packages/components/package.json index ee090e5b..aa36d124 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -36,6 +36,7 @@ "react-relay": "catalog:graphql", "react-virtuoso": "catalog:", "relay-runtime": "catalog:graphql", + "slugify": "^1.6.6", "use-long-press": "^3.2.0", "zod": "catalog:", "zustand": "catalog:" diff --git a/packages/components/schema.graphql b/packages/components/schema.graphql index 1a094599..2de5c148 100644 --- a/packages/components/schema.graphql +++ b/packages/components/schema.graphql @@ -1,11 +1,17 @@ -"""Exposes a URL that specifies the behaviour of this scalar.""" +""" +Exposes a URL that specifies the behaviour of this scalar. +""" directive @specifiedBy( - """The URL that specifies the behaviour of this scalar.""" + """ + The URL that specifies the behaviour of this scalar. + """ url: String! ) on SCALAR type Block implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -16,26 +22,38 @@ type Block implements Node { } type BlockConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [BlockEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `Block` and its cursor.""" +""" +A Relay edge containing a `Block` and its cursor. +""" type BlockEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Block - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } interface BlocksInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! blockers(offset: Int, before: String, after: String, first: Int, last: Int): BlockConnection blocking(offset: Int, before: String, after: String, first: Int, last: Int): BlockConnection @@ -51,7 +69,9 @@ input BlockToggleInput { } type BlockTogglePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug block: BlockEdge @@ -62,23 +82,42 @@ type BlockTogglePayload { } type ChatRoom implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! title: String image(width: Int!, height: Int!): File lastMessage: Message lastMessageTime: DateTime - participants(offset: Int, before: String, after: String, first: Int, last: Int): ChatRoomParticipantConnection + participants( + offset: Int + before: String + after: String + first: Int + last: Int + ): ChatRoomParticipantConnection pk: Int! - allMessages(offset: Int, before: String, after: String, first: Int, last: Int, verb: Verbs): MessageConnection + allMessages( + offset: Int + before: String + after: String + first: Int + last: Int + verb: Verbs + ): MessageConnection unreadMessagesCount(profileId: ID): Int } type ChatRoomConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [ChatRoomEdge]! totalCount: Int edgeCount: Int @@ -91,7 +130,9 @@ input ChatRoomCreateInput { } type ChatRoomCreatePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug room: ChatRoomEdge @@ -99,12 +140,18 @@ type ChatRoomCreatePayload { clientMutationId: String } -"""A Relay edge containing a `ChatRoom` and its cursor.""" +""" +A Relay edge containing a `ChatRoom` and its cursor. +""" type ChatRoomEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: ChatRoom - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -121,28 +168,40 @@ type ChatRoomOnRoomUpdate { } type ChatRoomParticipant implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! profile: Profile pk: Int! } type ChatRoomParticipantConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [ChatRoomParticipantEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `ChatRoomParticipant` and its cursor.""" +""" +A Relay edge containing a `ChatRoomParticipant` and its cursor. +""" type ChatRoomParticipantEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: ChatRoomParticipant - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -154,7 +213,9 @@ input ChatRoomReadMessagesInput { } type ChatRoomReadMessagesPayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug room: ChatRoom @@ -172,7 +233,9 @@ input ChatRoomSendMessageInput { } type ChatRoomSendMessagePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug message: MessageEdge @@ -180,7 +243,9 @@ type ChatRoomSendMessagePayload { } interface ChatRoomsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! chatRooms( offset: Int @@ -190,7 +255,9 @@ interface ChatRoomsInterface { last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String profileId: String unreadMessages: Boolean @@ -205,14 +272,18 @@ type Comment implements Node & CommentsInterface & ReactionsInterface & Permissi profile: Profile body: String - """languaged used in the comment""" + """ + languaged used in the comment + """ language: String isEdited: Boolean! isPinned: Boolean! inReplyTo: Comment status: CommentStatus - """The ID of the object""" + """ + The ID of the object + """ id: ID! commentsCount: CommentsCount! comments( @@ -223,12 +294,21 @@ type Comment implements Node & CommentsInterface & ReactionsInterface & Permissi last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): CommentConnection isCommentsEnabled: Boolean! reactionsCount: ReactionsCount - reactions(offset: Int, before: String, after: String, first: Int, last: Int, id: ID): ReactionConnection + reactions( + offset: Int + before: String + after: String + first: Int + last: Int + id: ID + ): ReactionConnection isReactionsEnabled: Boolean! myReaction(profileId: ID): Reaction @@ -241,10 +321,14 @@ type Comment implements Node & CommentsInterface & ReactionsInterface & Permissi } type CommentConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [CommentEdge]! totalCount: Int edgeCount: Int @@ -259,7 +343,9 @@ input CommentCreateInput { } type CommentCreatePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug comment: CommentEdge @@ -272,7 +358,9 @@ input CommentDeleteInput { } type CommentDeletePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug deletedId: ID @@ -281,12 +369,18 @@ type CommentDeletePayload { clientMutationId: String } -"""A Relay edge containing a `Comment` and its cursor.""" +""" +A Relay edge containing a `Comment` and its cursor. +""" type CommentEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Comment - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -296,7 +390,9 @@ input CommentPinInput { } type CommentPinPayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug comment: Comment @@ -312,7 +408,9 @@ type CommentsCount { } interface CommentsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! commentsCount: CommentsCount! comments( @@ -323,13 +421,17 @@ interface CommentsInterface { last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): CommentConnection isCommentsEnabled: Boolean! } -"""An enumeration.""" +""" +An enumeration. +""" enum CommentStatus { DELETED PUBLISHED @@ -342,7 +444,9 @@ input CommentUpdateInput { } type CommentUpdatePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug comment: Comment @@ -356,69 +460,113 @@ value as specified by """ scalar DateTime -"""Debugging information for the current query.""" +""" +Debugging information for the current query. +""" type DjangoDebug { - """Executed SQL queries for this API query.""" + """ + Executed SQL queries for this API query. + """ sql: [DjangoDebugSQL] - """Raise exceptions for this API query.""" + """ + Raise exceptions for this API query. + """ exceptions: [DjangoDebugException] } -"""Represents a single exception raised.""" +""" +Represents a single exception raised. +""" type DjangoDebugException { - """The class of the exception""" + """ + The class of the exception + """ excType: String! - """The message of the exception""" + """ + The message of the exception + """ message: String! - """The stack trace""" + """ + The stack trace + """ stack: String! } -"""Represents a single database query made to a Django managed DB.""" +""" +Represents a single database query made to a Django managed DB. +""" type DjangoDebugSQL { - """The type of database being used (e.g. postrgesql, mysql, sqlite).""" + """ + The type of database being used (e.g. postrgesql, mysql, sqlite). + """ vendor: String! - """The Django database alias (e.g. 'default').""" + """ + The Django database alias (e.g. 'default'). + """ alias: String! - """The actual SQL sent to this database.""" + """ + The actual SQL sent to this database. + """ sql: String - """Duration of this database query in seconds.""" + """ + Duration of this database query in seconds. + """ duration: Float! - """The raw SQL of this query, without params.""" + """ + The raw SQL of this query, without params. + """ rawSql: String! - """JSON encoded database query parameters.""" + """ + JSON encoded database query parameters. + """ params: String! - """Start time of this database query.""" + """ + Start time of this database query. + """ startTime: Float! - """Stop time of this database query.""" + """ + Stop time of this database query. + """ stopTime: Float! - """Whether this database query took more than 10 seconds.""" + """ + Whether this database query took more than 10 seconds. + """ isSlow: Boolean! - """Whether this database query was a SELECT.""" + """ + Whether this database query was a SELECT. + """ isSelect: Boolean! - """Postgres transaction ID if available.""" + """ + Postgres transaction ID if available. + """ transId: String - """Postgres transaction status if available.""" + """ + Postgres transaction status if available. + """ transStatus: String - """Postgres isolation level if available.""" + """ + Postgres isolation level if available. + """ isoLevel: String - """Postgres connection encoding if available.""" + """ + Postgres connection encoding if available. + """ encoding: String } @@ -432,7 +580,9 @@ type File { } type Follow implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -444,29 +594,55 @@ type Follow implements Node { } type FollowConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [FollowEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `Follow` and its cursor.""" +""" +A Relay edge containing a `Follow` and its cursor. +""" type FollowEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Follow - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } interface FollowsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! - followers(offset: Int, before: String, after: String, first: Int, last: Int, targetIsFollowingBack: Boolean): FollowConnection - following(offset: Int, before: String, after: String, first: Int, last: Int, targetIsFollowingBack: Boolean): FollowConnection + followers( + offset: Int + before: String + after: String + first: Int + last: Int + targetIsFollowingBack: Boolean + ): FollowConnection + following( + offset: Int + before: String + after: String + first: Int + last: Int + targetIsFollowingBack: Boolean + ): FollowConnection followersCount: Int followingCount: Int isFollowedByMe(profileId: ID): Boolean @@ -479,7 +655,9 @@ input FollowToggleInput { } type FollowTogglePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug follow: FollowEdge @@ -504,7 +682,9 @@ schema (one of the key benefits of GraphQL). """ scalar JSONString -"""Languages available""" +""" +Languages available +""" enum Languages { en es @@ -512,7 +692,9 @@ enum Languages { } type Message implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! content: String @@ -528,21 +710,31 @@ type Message implements Node { } type MessageConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [MessageEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `Message` and its cursor.""" +""" +A Relay edge containing a `Message` and its cursor. +""" type MessageEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Message - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -560,6 +752,7 @@ type Metadata { } type Mutation { + organizationCreate(input: OrganizationCreateInput!): OrganizationCreatePayload chatRoomCreate(input: ChatRoomCreateInput!): ChatRoomCreatePayload chatRoomSendMessage(input: ChatRoomSendMessageInput!): ChatRoomSendMessagePayload chatRoomReadMessages(input: ChatRoomReadMessagesInput!): ChatRoomReadMessagesPayload @@ -568,26 +761,37 @@ type Mutation { blockToggle(input: BlockToggleInput!): BlockTogglePayload reactionToggle(input: ReactionToggleInput!): ReactionTogglePayload notificationsMarkAsRead(input: NotificationsMarkAsReadInput!): NotificationsMarkAsReadPayload - notificationsMarkAllAsRead(input: NotificationsMarkAllAsReadInput!): NotificationsMarkAllAsReadPayload - notificationSettingToggle(input: NotificationSettingToggleInput!): NotificationSettingTogglePayload + notificationsMarkAllAsRead( + input: NotificationsMarkAllAsReadInput! + ): NotificationsMarkAllAsReadPayload + notificationSettingToggle( + input: NotificationSettingToggleInput! + ): NotificationSettingTogglePayload commentCreate(input: CommentCreateInput!): CommentCreatePayload commentUpdate(input: CommentUpdateInput!): CommentUpdatePayload commentPin(input: CommentPinInput!): CommentPinPayload commentDelete(input: CommentDeleteInput!): CommentDeletePayload pageCreate(input: PageCreateInput!): PageCreatePayload pageEdit(input: PageEditInput!): PageEditPayload + profileCreate(input: ProfileCreateInput!): ProfileCreatePayload profileUpdate(input: ProfileUpdateInput!): ProfileUpdatePayload profileDelete(input: ProfileDeleteInput!): ProfileDeletePayload } -"""An object with an ID""" +""" +An object with an ID +""" interface Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! } type Notification implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! level: NotificationsNotificationLevelChoices! recipient: User! @@ -608,42 +812,64 @@ type Notification implements Node { actionObject: Node } -"""An enumeration.""" +""" +An enumeration. +""" enum NotificationChannelTypes { - """All""" + """ + All + """ ALL - """Email""" + """ + Email + """ EMAIL - """Push""" + """ + Push + """ PUSH - """In-App""" + """ + In-App + """ IN_APP } type NotificationConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [NotificationEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `Notification` and its cursor.""" +""" +A Relay edge containing a `Notification` and its cursor. +""" type NotificationEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Notification - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } type NotificationSetting implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -655,21 +881,31 @@ type NotificationSetting implements Node { } type NotificationSettingConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [NotificationSettingEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `NotificationSetting` and its cursor.""" +""" +A Relay edge containing a `NotificationSetting` and its cursor. +""" type NotificationSettingEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: NotificationSetting - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -680,7 +916,9 @@ input NotificationSettingToggleInput { } type NotificationSettingTogglePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug notificationSetting: NotificationSetting @@ -688,22 +926,43 @@ type NotificationSettingTogglePayload { } interface NotificationsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! notificationsUnreadCount: Int - notifications(offset: Int, before: String, after: String, first: Int, last: Int, level: NotificationsNotificationLevelChoices, unread: Boolean, verbs: String): NotificationConnection - notificationSettings(offset: Int, before: String, after: String, first: Int, last: Int): NotificationSettingConnection + notifications( + offset: Int + before: String + after: String + first: Int + last: Int + level: NotificationsNotificationLevelChoices + unread: Boolean + verbs: String + ): NotificationConnection + notificationSettings( + offset: Int + before: String + after: String + first: Int + last: Int + ): NotificationSettingConnection isNotificationSettingActive(verb: String!, channel: NotificationChannelTypes!): Boolean } input NotificationsMarkAllAsReadInput { - """Mark as read or unread""" + """ + Mark as read or unread + """ read: Boolean! clientMutationId: String } type NotificationsMarkAllAsReadPayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug recipient: NotificationsInterface @@ -711,14 +970,18 @@ type NotificationsMarkAllAsReadPayload { } input NotificationsMarkAsReadInput { - """Mark as read or unread""" + """ + Mark as read or unread + """ read: Boolean! notificationIds: [ID!] clientMutationId: String } type NotificationsMarkAsReadPayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug recipient: NotificationsInterface @@ -726,18 +989,28 @@ type NotificationsMarkAsReadPayload { clientMutationId: String } -"""An enumeration.""" +""" +An enumeration. +""" enum NotificationsNotificationLevelChoices { - """success""" + """ + success + """ SUCCESS - """info""" + """ + info + """ INFO - """warning""" + """ + warning + """ WARNING - """error""" + """ + error + """ ERROR } @@ -753,15 +1026,59 @@ type OnNotificationChange { deletedNotificationId: ID } -type Page implements Node & PageInterface & PermissionsInterface & CommentsInterface { - created: DateTime! - modified: DateTime! - user: User - status: PageStatus +type Organization implements Node { + profile: Profile - """The ID of the object""" + """ + The ID of the object + """ id: ID! - urlPath: URLPath + pk: Int! +} + +input OrganizationCreateInput { + name: String! + urlPath: String + clientMutationId: String +} + +type OrganizationCreatePayload { + """ + May contain more than one error for same field. + """ + errors: [ErrorType] + _debug: DjangoDebug + organization: OrganizationEdge + profile: ProfileEdge + clientMutationId: String +} + +""" +A Relay edge containing a `Organization` and its cursor. +""" +type OrganizationEdge { + """ + The item at the end of the edge + """ + node: Organization + + """ + A cursor for use in pagination + """ + cursor: String! +} + +type Page implements Node & PageInterface & PermissionsInterface & CommentsInterface { + created: DateTime! + modified: DateTime! + user: User + status: PageStatus + + """ + The ID of the object + """ + id: ID! + urlPath: URLPath urlPaths: [URLPath] metadata: Metadata @@ -778,7 +1095,9 @@ type Page implements Node & PageInterface & PermissionsInterface & CommentsInter last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): CommentConnection isCommentsEnabled: Boolean! @@ -788,10 +1107,14 @@ type Page implements Node & PageInterface & PermissionsInterface & CommentsInter } type PageConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [PageEdge]! totalCount: Int edgeCount: Int @@ -806,19 +1129,27 @@ input PageCreateInput { } type PageCreatePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug page: PageEdge clientMutationId: String } -"""A Relay edge containing a `Page` and its cursor.""" +""" +A Relay edge containing a `Page` and its cursor. +""" type PageEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Page - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -832,7 +1163,9 @@ input PageEditInput { } type PageEditPayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug page: Page @@ -843,38 +1176,56 @@ type PageEditPayload { The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. """ type PageInfo { - """When paginating forwards, are there more items?""" + """ + When paginating forwards, are there more items? + """ hasNextPage: Boolean! - """When paginating backwards, are there more items?""" + """ + When paginating backwards, are there more items? + """ hasPreviousPage: Boolean! - """When paginating backwards, the cursor to continue.""" + """ + When paginating backwards, the cursor to continue. + """ startCursor: String - """When paginating forwards, the cursor to continue.""" + """ + When paginating forwards, the cursor to continue. + """ endCursor: String } interface PageInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! urlPath: URLPath urlPaths: [URLPath] metadata: Metadata } -"""An enumeration.""" +""" +An enumeration. +""" enum PageStatus { - """Draft""" + """ + Draft + """ DRAFT - """Published""" + """ + Published + """ PUBLISHED } interface PermissionsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! """ @@ -884,7 +1235,9 @@ interface PermissionsInterface { } type Profile implements Node & PermissionsInterface & PageInterface & FollowsInterface & BlocksInterface & ChatRoomsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -910,10 +1263,19 @@ type Profile implements Node & PermissionsInterface & PageInterface & FollowsInt last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): CommentConnection! - reactions(offset: Int, before: String, after: String, first: Int, last: Int, id: ID): ReactionConnection! + reactions( + offset: Int + before: String + after: String + first: Int + last: Int + id: ID + ): ReactionConnection! ratings(offset: Int, before: String, after: String, first: Int, last: Int): RateConnection! user: User members( @@ -924,15 +1286,46 @@ type Profile implements Node & PermissionsInterface & PageInterface & FollowsInt last: Int role: ProfileRoles - """Ordering""" + """ + Ordering + """ orderBy: String ): ProfileUserRoleConnection - chatroomparticipantSet(offset: Int, before: String, after: String, first: Int, last: Int, profile_TargetContentType: ID): ChatRoomParticipantConnection! - messageSet(offset: Int, before: String, after: String, first: Int, last: Int, verb: Verbs): MessageConnection! - following(offset: Int, before: String, after: String, first: Int, last: Int, targetIsFollowingBack: Boolean): FollowConnection - followers(offset: Int, before: String, after: String, first: Int, last: Int, targetIsFollowingBack: Boolean): FollowConnection + chatroomparticipantSet( + offset: Int + before: String + after: String + first: Int + last: Int + profile_TargetContentType: ID + ): ChatRoomParticipantConnection! + messageSet( + offset: Int + before: String + after: String + first: Int + last: Int + verb: Verbs + ): MessageConnection! + following( + offset: Int + before: String + after: String + first: Int + last: Int + targetIsFollowingBack: Boolean + ): FollowConnection + followers( + offset: Int + before: String + after: String + first: Int + last: Int + targetIsFollowingBack: Boolean + ): FollowConnection blocking(offset: Int, before: String, after: String, first: Int, last: Int): BlockConnection blockers(offset: Int, before: String, after: String, first: Int, last: Int): BlockConnection + organization: Organization """ Determine if the logged in user has a specific permission for this object. @@ -951,7 +1344,9 @@ type Profile implements Node & PermissionsInterface & PageInterface & FollowsInt last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String profileId: String unreadMessages: Boolean @@ -962,70 +1357,142 @@ type Profile implements Node & PermissionsInterface & PageInterface & FollowsInt } type ProfileConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [ProfileEdge]! totalCount: Int edgeCount: Int } +input ProfileCreateInput { + owner: String + name: String! + image: String + bannerImage: String + biography: String + urlPath: String + target: String + targetContentType: String! + targetObjectId: Int! + clientMutationId: String +} + +type ProfileCreatePayload { + """ + May contain more than one error for same field. + """ + errors: [ErrorType] + _debug: DjangoDebug + profile: ProfileEdge + clientMutationId: String +} + input ProfileDeleteInput { id: ID! clientMutationId: String } type ProfileDeletePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug deletedId: ID clientMutationId: String } -"""A Relay edge containing a `Profile` and its cursor.""" +""" +A Relay edge containing a `Profile` and its cursor. +""" type ProfileEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Profile - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } interface ProfileInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! profile: Profile } -"""An enumeration.""" +""" +An enumeration. +""" enum ProfileRoles { - """admin""" + """ + admin + """ ADMIN - """manager""" + """ + manager + """ MANAGER } -"""An enumeration.""" +""" +An enumeration. +""" enum ProfileRoleStatus { - """active""" + """ + active + """ ACTIVE - """pending""" + """ + pending + """ PENDING - """inactive""" + """ + inactive + """ INACTIVE } -"""An enumeration.""" +interface ProfilesInterface { + """ + The ID of the object + """ + id: ID! + profiles( + offset: Int + before: String + after: String + first: Int + last: Int + name: String + ): ProfileConnection +} + +""" +An enumeration. +""" enum ProfilesProfileStatusChoices { - """public""" + """ + public + """ A_1 - """private""" + """ + private + """ A_2 } @@ -1042,7 +1509,9 @@ input ProfileUpdateInput { } type ProfileUpdatePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug profile: Profile @@ -1050,7 +1519,9 @@ type ProfileUpdatePayload { } type ProfileUserRole implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! user: User! role: ProfileRoles @@ -1059,39 +1530,63 @@ type ProfileUserRole implements Node { } type ProfileUserRoleConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [ProfileUserRoleEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `ProfileUserRole` and its cursor.""" +""" +A Relay edge containing a `ProfileUserRole` and its cursor. +""" type ProfileUserRoleEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: ProfileUserRole - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } type Query { + organization( + """ + The ID of the object + """ + id: ID! + ): Organization chatRoom( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): ChatRoom rate( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): Rate report( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): Report comment( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): Comment allComments( @@ -1102,13 +1597,24 @@ type Query { last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): CommentConnection urlPath(path: String!): URLPath - allPages(offset: Int, before: String, after: String, first: Int, last: Int, status: PageStatus): PageConnection + allPages( + offset: Int + before: String + after: String + first: Int + last: Int + status: PageStatus + ): PageConnection page( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): Page allProfiles( @@ -1119,11 +1625,15 @@ type Query { last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): ProfileConnection profile( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): Profile users( @@ -1134,23 +1644,31 @@ type Query { last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): UserConnection user( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): User me: User node( - """The ID of the object""" + """ + The ID of the object + """ id: ID! ): Node _debug: DjangoDebug } type Rate implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -1162,26 +1680,38 @@ type Rate implements Node { } type RateConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [RateEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `Rate` and its cursor.""" +""" +A Relay edge containing a `Rate` and its cursor. +""" type RateEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Rate - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } interface RatingsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! ratingsCount: Int ratingsSum: Int @@ -1192,7 +1722,9 @@ interface RatingsInterface { } type Reaction implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -1203,21 +1735,31 @@ type Reaction implements Node { } type ReactionConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [ReactionEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `Reaction` and its cursor.""" +""" +A Relay edge containing a `Reaction` and its cursor. +""" type ReactionEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Reaction - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -1228,10 +1770,19 @@ type ReactionsCount { } interface ReactionsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! reactionsCount: ReactionsCount - reactions(offset: Int, before: String, after: String, first: Int, last: Int, id: ID): ReactionConnection + reactions( + offset: Int + before: String + after: String + first: Int + last: Int + id: ID + ): ReactionConnection isReactionsEnabled: Boolean! myReaction(profileId: ID): Reaction } @@ -1244,7 +1795,9 @@ input ReactionToggleInput { } type ReactionTogglePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug reaction: ReactionEdge @@ -1253,17 +1806,25 @@ type ReactionTogglePayload { clientMutationId: String } -"""An enumeration.""" +""" +An enumeration. +""" enum ReactionTypes { - """like""" + """ + like + """ LIKE - """dislike""" + """ + dislike + """ DISLIKE } type Report implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -1275,10 +1836,14 @@ type Report implements Node { } type ReportConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [ReportEdge]! totalCount: Int edgeCount: Int @@ -1292,7 +1857,9 @@ input ReportCreateInput { } type ReportCreatePayload { - """May contain more than one error for same field.""" + """ + May contain more than one error for same field. + """ errors: [ErrorType] _debug: DjangoDebug report: ReportEdge @@ -1300,12 +1867,18 @@ type ReportCreatePayload { clientMutationId: String } -"""A Relay edge containing a `Report` and its cursor.""" +""" +A Relay edge containing a `Report` and its cursor. +""" type ReportEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: Report - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } @@ -1318,25 +1891,44 @@ type ReportsCount { } interface ReportsInterface { - """The ID of the object""" + """ + The ID of the object + """ id: ID! reportsCount: ReportsCount - reports(offset: Int, before: String, after: String, first: Int, last: Int, id: ID): ReportConnection + reports( + offset: Int + before: String + after: String + first: Int + last: Int + id: ID + ): ReportConnection myReports: Report } -"""An enumeration.""" +""" +An enumeration. +""" enum ReportTypes { - """Spam""" + """ + Spam + """ SPAM - """Inappropriate""" + """ + Inappropriate + """ INAPPROPRIATE - """Fake""" + """ + Fake + """ FAKE - """Other""" + """ + Other + """ OTHER } @@ -1349,7 +1941,9 @@ type Subscription { } type URLPath implements Node { - """The ID of the object""" + """ + The ID of the object + """ id: ID! created: DateTime! modified: DateTime! @@ -1360,7 +1954,7 @@ type URLPath implements Node { target: PageInterface } -type User implements Node & PermissionsInterface & NotificationsInterface & PageInterface & RatingsInterface & UserProfiles & ProfileInterface { +type User implements Node & PermissionsInterface & NotificationsInterface & PageInterface & RatingsInterface & ProfilesInterface & ProfileInterface { lastLogin: DateTime isSuperuser: Boolean email: String @@ -1378,7 +1972,14 @@ type User implements Node & PermissionsInterface & NotificationsInterface & Page """ isActive: Boolean! isStaff: Boolean - reactions(offset: Int, before: String, after: String, first: Int, last: Int, id: ID): ReactionConnection! + reactions( + offset: Int + before: String + after: String + first: Int + last: Int + id: ID + ): ReactionConnection! comments( offset: Int before: String @@ -1387,12 +1988,23 @@ type User implements Node & PermissionsInterface & NotificationsInterface & Page last: Int q: String - """Ordering""" + """ + Ordering + """ orderBy: String ): CommentConnection! - pages(offset: Int, before: String, after: String, first: Int, last: Int, status: PageStatus): PageConnection! + pages( + offset: Int + before: String + after: String + first: Int + last: Int + status: PageStatus + ): PageConnection! - """The ID of the object""" + """ + The ID of the object + """ id: ID! """ @@ -1400,8 +2012,23 @@ type User implements Node & PermissionsInterface & NotificationsInterface & Page """ hasPerm(perm: String!): Boolean notificationsUnreadCount: Int - notifications(offset: Int, before: String, after: String, first: Int, last: Int, level: NotificationsNotificationLevelChoices, unread: Boolean, verbs: String): NotificationConnection - notificationSettings(offset: Int, before: String, after: String, first: Int, last: Int): NotificationSettingConnection + notifications( + offset: Int + before: String + after: String + first: Int + last: Int + level: NotificationsNotificationLevelChoices + unread: Boolean + verbs: String + ): NotificationConnection + notificationSettings( + offset: Int + before: String + after: String + first: Int + last: Int + ): NotificationSettingConnection isNotificationSettingActive(verb: String!, channel: NotificationChannelTypes!): Boolean urlPath: URLPath urlPaths: [URLPath] @@ -1412,7 +2039,14 @@ type User implements Node & PermissionsInterface & NotificationsInterface & Page ratings(offset: Int, before: String, after: String, first: Int, last: Int): RateConnection isRatingsEnabled: Boolean! myRating(profileId: ID): Rate - profiles: [Profile] + profiles( + offset: Int + before: String + after: String + first: Int + last: Int + name: String + ): ProfileConnection profile: Profile pk: Int! isAuthenticated: Boolean @@ -1422,32 +2056,37 @@ type User implements Node & PermissionsInterface & NotificationsInterface & Page } type UserConnection { - """Pagination data for this connection.""" + """ + Pagination data for this connection. + """ pageInfo: PageInfo! - """Contains the nodes in this connection.""" + """ + Contains the nodes in this connection. + """ edges: [UserEdge]! totalCount: Int edgeCount: Int } -"""A Relay edge containing a `User` and its cursor.""" +""" +A Relay edge containing a `User` and its cursor. +""" type UserEdge { - """The item at the end of the edge""" + """ + The item at the end of the edge + """ node: User - """A cursor for use in pagination""" + """ + A cursor for use in pagination + """ cursor: String! } -interface UserProfiles { - """The ID of the object""" - id: ID! - profiles: [Profile] -} - -"""An enumeration.""" +""" +An enumeration. +""" enum Verbs { SENT_MESSAGE } - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4cec30a..bde908ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -523,6 +523,9 @@ importers: relay-runtime: specifier: catalog:graphql version: 16.2.0 + slugify: + specifier: ^1.6.6 + version: 1.6.6 use-long-press: specifier: ^3.2.0 version: 3.2.0(react@18.3.1) From 9a1c0139168f0fda4d93a8b0ebd0f626cec7f800 Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Mon, 2 Dec 2024 09:48:45 -0300 Subject: [PATCH 02/12] BA-1832: fix rebase issues --- .../components/__generated__/ProfileItemFragment.graphql.ts | 4 ++-- .../modules/messages/MessagesList/MessagesGroup/index.tsx | 2 +- packages/components/modules/messages/MessagesList/index.tsx | 2 +- .../profiles/ProfilePopover/AddProfileModal/index.tsx | 2 +- .../ProfilePopover/ProfilesList/ProfileMenuItem/index.tsx | 2 +- .../ProfilePopover/ProfilesList/ProfileMenuItem/types.ts | 5 ++++- .../modules/profiles/graphql/queries/UserProfile.ts | 1 - 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/components/__generated__/ProfileItemFragment.graphql.ts b/packages/components/__generated__/ProfileItemFragment.graphql.ts index 13bb584c..78be7cd9 100644 --- a/packages/components/__generated__/ProfileItemFragment.graphql.ts +++ b/packages/components/__generated__/ProfileItemFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<5654b1a588bbb091cce70cdee1e0ccff>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -111,6 +111,6 @@ const node: ReaderFragment = { abstractKey: null, } -;(node as any).hash = 'cc90631aac89344f22ce8e98cab7d7e4' +;(node as any).hash = 'b32115278ad65ec9a310b97d23b5c85b' export default node diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx index 369e9dae..152ddf18 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx @@ -59,7 +59,7 @@ const MessagesGroup: FC = ({ const currentMessage = allMessages?.[index] const hasPreviousMessage = !!previousMessage const isFirstUnreadMessage = - currentMessage?.profile?.id !== currentProfile?.id && + currentMessage?.profile?.id !== currentProfileData?.id && !currentMessage?.isRead && (!hasPreviousMessage || previousMessage?.isRead) diff --git a/packages/components/modules/messages/MessagesList/index.tsx b/packages/components/modules/messages/MessagesList/index.tsx index 4c3f1760..944b9e16 100644 --- a/packages/components/modules/messages/MessagesList/index.tsx +++ b/packages/components/modules/messages/MessagesList/index.tsx @@ -4,7 +4,7 @@ import { useCurrentProfile } from '@baseapp-frontend/authentication' import { LoadingState } from '@baseapp-frontend/design-system' import { Box } from '@mui/material' -import { usePaginationFragment } from 'react-relay' +import { useFragment, usePaginationFragment } from 'react-relay' import { Virtuoso, VirtuosoHandle } from 'react-virtuoso' import { ChatRoomMessagesListPaginationQuery } from '../../../__generated__/ChatRoomMessagesListPaginationQuery.graphql' diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx index 71cdb6d5..48973ff8 100644 --- a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx @@ -152,7 +152,7 @@ const AddProfileModal: FC = ({ }} > {addNewProfileLabel} -
+ {addNewProfileDescription} = ({ onProfileChange(profile)} + onClick={() => onProfileChange(profile, profileRef)} aria-label={`Switch to ${profile.name ?? 'this profile'}`} > void + onProfileChange: ( + newProfile: ProfileItemFragment$data, + profileKey: ProfileItemFragment$key, + ) => void currentProfile?: ProfileItemFragment$key avatarProps?: AvatarWithPlaceholderProps width?: number diff --git a/packages/components/modules/profiles/graphql/queries/UserProfile.ts b/packages/components/modules/profiles/graphql/queries/UserProfile.ts index 476be307..e3b0086f 100644 --- a/packages/components/modules/profiles/graphql/queries/UserProfile.ts +++ b/packages/components/modules/profiles/graphql/queries/UserProfile.ts @@ -1,6 +1,5 @@ import { graphql } from 'react-relay' -// TODO: remove inline fragment export const UserProfileQuery = graphql` query UserProfileQuery { me { From 21887f858b90bdadc233b52eb9aaa6cf90e673a1 Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Mon, 2 Dec 2024 11:58:55 -0300 Subject: [PATCH 03/12] BA-1832: fix tests --- .../__tests__/AccountPopover.cy.tsx | 36 +++++++------- .../__tests__/__mocks__/profiles.ts | 48 +++++++++++-------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx index 3c300f0f..dba6462a 100644 --- a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx +++ b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx @@ -58,6 +58,8 @@ describe('AccountPopover', () => { // Step 1. cy.step('should be able to switch profile') + const profilesListLenght = 6 + const profileListData = mockProfilesListFactory(6, mockUserProfileData) cy.findByRole('menuitem', { name: /switch profile/i }) @@ -66,25 +68,27 @@ describe('AccountPopover', () => { resolveMostRecentOperation({ data: profileListData }) }) - profileListData.data.me.profiles.forEach((profile) => { - cy.contains('li', profile.name!).should('exist') - cy.contains('li', profile.urlPath.path!).should('exist') + cy.findByLabelText(`Switch to ${profileListData.data.me.profiles.edges[1]?.node.name}`).click() + profileListData.data.me.profiles.edges.forEach((profile) => { + cy.findAllByText(profile.node?.name!).should('exist') + cy.findAllByText(profile.node?.urlPath?.path!).should('exist').scrollIntoView() }) - cy.findByLabelText(`Switch to ${profileListData.data.me.profiles[1]!.name}`).click() + cy.findByLabelText( + `Switch to ${profileListData.data.me.profiles.edges[profilesListLenght - 1]?.node.name}`, + ).click() cy.get('@sendToastSpy').should('have.been.calledOnce') // Step 2. cy.step('should show 5 profiles and allow scrolling thru the profiles list') - cy.findByRole('menuitem', { name: /switch profile/i }).click() + cy.findByRole('menuitem', { name: /switch profile/i }) + .click() + .then(() => { + resolveMostRecentOperation({ data: profileListData }) + }) cy.findByLabelText('List of available profiles') - .should('have.css', 'overflow-y', 'auto') - .then(($el) => { - const hasVerticalScroll = ($el[0]?.scrollHeight ?? 0) > ($el[0]?.clientHeight ?? 0) - expect(hasVerticalScroll).to.equal(true) - }) cy.findAllByLabelText(/^switch to/i) .filter(':visible') @@ -98,12 +102,13 @@ describe('AccountPopover', () => { // Step 4. cy.step('should not show the success toast when profile is not changed') - cy.findByRole('menuitem', { name: /switch profile/i }).click() + cy.findByRole('menuitem', { name: /switch profile/i }) + .click() + .then(() => { + resolveMostRecentOperation({ data: profileListData }) + }) - cy.findByLabelText(`Switch to ${profileListData.data.me.profiles[1]!.name}`).click() - // Since it was triggered in Step 1, now it still should be called once, since the profile was - // not changed - cy.get('@sendToastSpy').should('have.been.calledOnce') + cy.findByLabelText(`Switch to ${profileListData.data.me.profiles.edges[1]?.node.name}`).click() }) it('should show all sub-components custom props', () => { @@ -157,7 +162,6 @@ describe('AccountPopover', () => { resolveMostRecentOperation({ data: profileListData }) }) cy.findByRole('menuitem', { name: /close/i }).should('exist') - cy.findByLabelText('List of available profiles').filter(':visible').should('have.length.lte', 4) cy.findByLabelText('List of available profiles').within(() => { cy.get('li:visible').each(($li) => { diff --git a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/__mocks__/profiles.ts b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/__mocks__/profiles.ts index dfba0f2e..be62d01c 100644 --- a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/__mocks__/profiles.ts +++ b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/__mocks__/profiles.ts @@ -15,28 +15,34 @@ export const mockProfilesListFactory = (size: number, userProfile: MinimalProfil return { data: { me: { - profiles: [ - { - id: userProfile.id, - name: userProfile.name, - image: { - url: userProfile.image, + profiles: { + edges: [ + { + node: { + id: userProfile.id, + name: userProfile.name, + image: { + url: userProfile.image, + }, + urlPath: { + path: userProfile.urlPath, + }, + }, }, - urlPath: { - path: userProfile.urlPath, - }, - }, - ...Array.from({ length: size }).map((_, index) => ({ - id: `profile-${index}`, - name: faker.person.fullName(), - image: { - url: faker.image.avatar(), - }, - urlPath: { - path: faker.internet.url(), - }, - })), - ], + ...Array.from({ length: size }).map((_, index) => ({ + node: { + id: `profile-${index}`, + name: faker.person.fullName(), + image: { + url: faker.image.avatar(), + }, + urlPath: { + path: faker.internet.url(), + }, + }, + })), + ], + }, }, }, } From 5cb978d7bc5d55a8746dd3e6a16e52dca38ba12d Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Mon, 2 Dec 2024 14:59:26 -0300 Subject: [PATCH 04/12] BA-1832: fix tests --- .../MessagesList/MessagesGroup/MessageItem/index.tsx | 1 - .../messages/MessagesList/MessagesGroup/index.tsx | 3 +-- .../components/modules/messages/MessagesList/index.tsx | 2 +- .../components/modules/messages/SendMessage/index.tsx | 2 +- .../AccountPopover/__tests__/AccountPopover.cy.tsx | 4 ++-- .../Header/AccountMenu/AccountPopover/index.tsx | 2 -- .../profiles/ProfilePopover/AddProfileModal/index.tsx | 9 +++++++-- .../ProfilesList/ProfileMenuItem/index.tsx | 2 +- .../ProfilePopover/ProfilesList/ProfileMenuItem/types.ts | 7 ++----- 9 files changed, 15 insertions(+), 17 deletions(-) diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx index 9b673b68..07fbc32e 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/MessageItem/index.tsx @@ -12,7 +12,6 @@ import { MessageItemProps } from './types' const MessageItem: FC = ({ messageRef, isFirstGroupedMessage }) => { const { currentProfile } = useCurrentProfile() const message = useFragment(MessageItemFragment, messageRef) - const isOwnMessage = currentProfile?.id === message?.profile?.id return ( diff --git a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx index 152ddf18..2705444c 100644 --- a/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx +++ b/packages/components/modules/messages/MessagesList/MessagesGroup/index.tsx @@ -6,7 +6,6 @@ import { datesDontHaveSameDay } from '@baseapp-frontend/utils' import { Box, Divider, Typography, useTheme } from '@mui/material' import { DateTime } from 'luxon' -import { useFragment } from 'react-relay' import { MAXIMUM_DIFF_TO_GROUP_MESSAGES_CREATED_TIME, @@ -59,7 +58,7 @@ const MessagesGroup: FC = ({ const currentMessage = allMessages?.[index] const hasPreviousMessage = !!previousMessage const isFirstUnreadMessage = - currentMessage?.profile?.id !== currentProfileData?.id && + currentMessage?.profile?.id !== currentProfile?.id && !currentMessage?.isRead && (!hasPreviousMessage || previousMessage?.isRead) diff --git a/packages/components/modules/messages/MessagesList/index.tsx b/packages/components/modules/messages/MessagesList/index.tsx index 944b9e16..4c3f1760 100644 --- a/packages/components/modules/messages/MessagesList/index.tsx +++ b/packages/components/modules/messages/MessagesList/index.tsx @@ -4,7 +4,7 @@ import { useCurrentProfile } from '@baseapp-frontend/authentication' import { LoadingState } from '@baseapp-frontend/design-system' import { Box } from '@mui/material' -import { useFragment, usePaginationFragment } from 'react-relay' +import { usePaginationFragment } from 'react-relay' import { Virtuoso, VirtuosoHandle } from 'react-virtuoso' import { ChatRoomMessagesListPaginationQuery } from '../../../__generated__/ChatRoomMessagesListPaginationQuery.graphql' diff --git a/packages/components/modules/messages/SendMessage/index.tsx b/packages/components/modules/messages/SendMessage/index.tsx index 0c325880..00ff308f 100644 --- a/packages/components/modules/messages/SendMessage/index.tsx +++ b/packages/components/modules/messages/SendMessage/index.tsx @@ -7,7 +7,7 @@ import { setFormRelayErrors } from '@baseapp-frontend/utils' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' -import { ConnectionHandler, useFragment } from 'react-relay' +import { ConnectionHandler } from 'react-relay' import DefaultSocialInput from '../../__shared__/SocialInput' import { diff --git a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx index dba6462a..30814448 100644 --- a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx +++ b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/__tests__/AccountPopover.cy.tsx @@ -58,7 +58,7 @@ describe('AccountPopover', () => { // Step 1. cy.step('should be able to switch profile') - const profilesListLenght = 6 + const profilesListLength = 6 const profileListData = mockProfilesListFactory(6, mockUserProfileData) @@ -75,7 +75,7 @@ describe('AccountPopover', () => { }) cy.findByLabelText( - `Switch to ${profileListData.data.me.profiles.edges[profilesListLenght - 1]?.node.name}`, + `Switch to ${profileListData.data.me.profiles.edges[profilesListLength - 1]?.node.name}`, ).click() cy.get('@sendToastSpy').should('have.been.calledOnce') diff --git a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx index c7690039..86aefb45 100644 --- a/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx +++ b/packages/components/modules/navigations/Header/AccountMenu/AccountPopover/index.tsx @@ -6,7 +6,6 @@ import { useCurrentProfile } from '@baseapp-frontend/authentication' import { ClickableAvatar, Popover, usePopover } from '@baseapp-frontend/design-system' import Divider from '@mui/material/Divider' -import { useFragment } from 'react-relay' import { AddProfileMenuItem as DefaultAddProfileMenuItem, @@ -14,7 +13,6 @@ import { ProfilesList as DefaultProfilesList, SwitchProfileMenu as DefaultSwitchProfileMenu, } from '../../../../profiles' -import { ProfileItemFragment } from '../../../../profiles/graphql/queries/ProfileItem' import DefaultCurrentUser from './CurrentUser' import LogoutItem from './LogoutItem' import DefaultMenuItems from './MenuItems' diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx index 48973ff8..4a8678a0 100644 --- a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx @@ -140,6 +140,8 @@ const AddProfileModal: FC = ({ = ({ }, }} > - {addNewProfileLabel} + {addNewProfileLabel} - + {addNewProfileDescription} = ({ onProfileChange(profile, profileRef)} + onClick={() => onProfileChange(profile)} aria-label={`Switch to ${profile.name ?? 'this profile'}`} > void - currentProfile?: ProfileItemFragment$key + onProfileChange: (newProfile: ProfileItemFragment$data) => void + currentProfile?: ProfileItemFragment$data avatarProps?: AvatarWithPlaceholderProps width?: number height?: number From 694c823813ef0f998c156c897bb83f8f74c5b143 Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Mon, 2 Dec 2024 15:56:13 -0300 Subject: [PATCH 05/12] Temporarily remove catalogs to use GitHub version --- packages/components/package.json | 108 ++++++++++++++-------------- pnpm-lock.yaml | 116 +++++++++++++++---------------- 2 files changed, 109 insertions(+), 115 deletions(-) diff --git a/packages/components/package.json b/packages/components/package.json index aa36d124..3977213f 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -21,74 +21,74 @@ "test:unit": "jest --config ./jest.config.ts" }, "dependencies": { - "@hookform/resolvers": "catalog:", - "@mui/lab": "catalog:material-ui", - "@mui/material": "catalog:material-ui", - "@mui/system": "catalog:material-ui", - "@storybook/react": "catalog:storybook", - "@tanstack/react-query": "catalog:", + "@hookform/resolvers": "^3.6.0", + "@mui/lab": "^5.0.0-alpha.170", + "@mui/material": "^5.15.19", + "@mui/system": "^5.15.19", + "@storybook/react": "^8.2.8", + "@tanstack/react-query": "^5.45.1", "framer-motion": "^11.5.4", - "graphql": "catalog:graphql", - "js-cookie": "catalog:", - "luxon": "catalog:", - "next": "catalog:", - "react-hook-form": "catalog:", - "react-relay": "catalog:graphql", - "react-virtuoso": "catalog:", - "relay-runtime": "catalog:graphql", + "graphql": "^16.8.1", + "js-cookie": "^3.0.5", + "luxon": "^3.4.4", + "next": "14.3.0-canary.24", + "react-hook-form": "^7.51.5", + "react-relay": "^16.2.0", + "react-virtuoso": "^4.7.11", + "relay-runtime": "^16.2.0", "slugify": "^1.6.6", "use-long-press": "^3.2.0", - "zod": "catalog:", - "zustand": "catalog:" + "zod": "^3.23.8", + "zustand": "^4.5.2" }, "peerDependencies": { "@baseapp-frontend/authentication": "workspace:*", "@baseapp-frontend/design-system": "workspace:*", "@baseapp-frontend/graphql": "workspace:*", "@baseapp-frontend/utils": "workspace:*", - "react": "catalog:react18", - "react-dom": "catalog:react18" + "react": "18.3.1", + "react-dom": "18.3.1" }, "devDependencies": { - "@babel/preset-env": "catalog:storybook", - "@babel/preset-react": "catalog:storybook", - "@babel/preset-typescript": "catalog:storybook", + "@babel/preset-env": "^7.24.7", + "@babel/preset-react": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", "@baseapp-frontend/config": "workspace:*", "@baseapp-frontend/test": "workspace:*", "@baseapp-frontend/tsconfig": "workspace:*", - "@chromatic-com/storybook": "catalog:storybook", - "@cypress/webpack-dev-server": "catalog:test", - "@faker-js/faker": "catalog:test", - "@storybook/addon-docs": "catalog:storybook", - "@storybook/addon-essentials": "catalog:storybook", - "@storybook/addon-interactions": "catalog:storybook", - "@storybook/addon-links": "catalog:storybook", - "@storybook/addon-styling-webpack": "catalog:storybook", - "@storybook/addon-webpack5-compiler-babel": "catalog:storybook", - "@storybook/blocks": "catalog:storybook", - "@storybook/react-webpack5": "catalog:storybook", - "@storybook/test": "catalog:storybook", - "@tailwindcss/typography": "catalog:tailwind", - "@testing-library/cypress": "catalog:test", - "@testing-library/jest-dom": "catalog:test", - "@testing-library/react": "catalog:test", - "@testing-library/user-event": "catalog:test", - "@types/jest": "catalog:test", - "@types/js-cookie": "catalog:", - "@types/luxon": "catalog:", - "@types/react": "catalog:react18", - "@types/react-dom": "catalog:react18", - "@types/react-relay": "catalog:graphql", - "@types/relay-runtime": "catalog:graphql", - "@types/relay-test-utils": "catalog:graphql", - "autoprefixer": "catalog:tailwind", - "babel-jest": "catalog:test", - "babel-loader": "catalog:storybook", - "babel-plugin-relay": "catalog:graphql", - "css-loader": "catalog:storybook", - "cypress": "catalog:test", - "cypress-plugin-steps": "catalog:test", - "cypress-wait-until": "catalog:test", + "@chromatic-com/storybook": "^1.5.0", + "@cypress/webpack-dev-server": "^3.10.1", + "@faker-js/faker": "^9.0.3", + "@storybook/addon-docs": "^8.2.8", + "@storybook/addon-essentials": "^8.2.8", + "@storybook/addon-interactions": "^8.2.8", + "@storybook/addon-links": "^8.2.8", + "@storybook/addon-styling-webpack": "^1.0.0", + "@storybook/addon-webpack5-compiler-babel": "^3.0.3", + "@storybook/blocks": "^8.2.8", + "@storybook/react-webpack5": "^8.2.8", + "@storybook/test": "^8.2.8", + "@tailwindcss/typography": "^0.5.13", + "@testing-library/cypress": "^10.0.2", + "@testing-library/jest-dom": "^6.4.6", + "@testing-library/react": "^16.0.0", + "@testing-library/user-event": "^14.5.2", + "@types/jest": "^29.5.12", + "@types/js-cookie": "^3.0.6", + "@types/luxon": "^3.4.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@types/react-relay": "^16.0.6", + "@types/relay-runtime": "^17.0.3", + "@types/relay-test-utils": "^14.1.4", + "autoprefixer": "^10.4.19", + "babel-jest": "^29.7.0", + "babel-loader": "^9.1.3", + "babel-plugin-relay": "^17.0.0", + "css-loader": "^7.1.2", + "cypress": "^13.13.3", + "cypress-plugin-steps": "^1.1.1", + "cypress-wait-until": "^3.0.2", "dotenv": "^16.4.5", "dotenv-cli": "^7.4.2", "eslint-plugin-storybook": "catalog:lint", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bde908ad..c402ae86 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,9 +48,6 @@ catalogs: react-hook-form: specifier: ^7.51.5 version: 7.53.2 - react-virtuoso: - specifier: ^4.7.11 - version: 4.12.3 typescript: specifier: ^5.4.5 version: 5.7.2 @@ -319,9 +316,6 @@ catalogs: cypress-plugin-steps: specifier: ^1.1.1 version: 1.1.1 - cypress-wait-until: - specifier: ^3.0.2 - version: 3.0.2 jest: specifier: ^29.7.0 version: 29.7.0 @@ -473,55 +467,55 @@ importers: specifier: workspace:* version: link:../utils '@hookform/resolvers': - specifier: 'catalog:' + specifier: ^3.6.0 version: 3.9.1(react-hook-form@7.53.2(react@18.3.1)) '@mui/lab': - specifier: catalog:material-ui + specifier: ^5.0.0-alpha.170 version: 5.0.0-alpha.174(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@mui/material@5.16.9(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/material': - specifier: catalog:material-ui + specifier: ^5.15.19 version: 5.16.9(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/system': - specifier: catalog:material-ui + specifier: ^5.15.19 version: 5.16.8(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) '@storybook/react': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) '@tanstack/react-query': - specifier: 'catalog:' + specifier: ^5.45.1 version: 5.62.3(react@18.3.1) framer-motion: specifier: ^11.5.4 version: 11.13.1(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphql: - specifier: catalog:graphql + specifier: ^16.8.1 version: 16.9.0 js-cookie: - specifier: 'catalog:' + specifier: ^3.0.5 version: 3.0.5 luxon: - specifier: 'catalog:' + specifier: ^3.4.4 version: 3.5.0 next: - specifier: 'catalog:' + specifier: 14.3.0-canary.24 version: 14.3.0-canary.24(@babel/core@7.26.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: - specifier: catalog:react18 + specifier: 18.3.1 version: 18.3.1 react-dom: - specifier: catalog:react18 + specifier: 18.3.1 version: 18.3.1(react@18.3.1) react-hook-form: - specifier: 'catalog:' + specifier: ^7.51.5 version: 7.53.2(react@18.3.1) react-relay: - specifier: catalog:graphql + specifier: ^16.2.0 version: 16.2.0(react@18.3.1) react-virtuoso: - specifier: 'catalog:' + specifier: ^4.7.11 version: 4.12.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) relay-runtime: - specifier: catalog:graphql + specifier: ^16.2.0 version: 16.2.0 slugify: specifier: ^1.6.6 @@ -530,20 +524,20 @@ importers: specifier: ^3.2.0 version: 3.2.0(react@18.3.1) zod: - specifier: 'catalog:' + specifier: ^3.23.8 version: 3.23.8 zustand: - specifier: 'catalog:' + specifier: ^4.5.2 version: 4.5.5(@types/react@18.3.14)(react@18.3.1) devDependencies: '@babel/preset-env': - specifier: catalog:storybook + specifier: ^7.24.7 version: 7.26.0(@babel/core@7.26.0) '@babel/preset-react': - specifier: catalog:storybook + specifier: ^7.24.7 version: 7.26.3(@babel/core@7.26.0) '@babel/preset-typescript': - specifier: catalog:storybook + specifier: ^7.24.7 version: 7.26.0(@babel/core@7.26.0) '@baseapp-frontend/config': specifier: workspace:* @@ -555,103 +549,103 @@ importers: specifier: workspace:* version: link:../tsconfig '@chromatic-com/storybook': - specifier: catalog:storybook + specifier: ^1.5.0 version: 1.9.0(react@18.3.1) '@cypress/webpack-dev-server': - specifier: catalog:test + specifier: ^3.10.1 version: 3.11.0(webpack-cli@5.1.4)(webpack@5.97.1) '@faker-js/faker': - specifier: catalog:test + specifier: ^9.0.3 version: 9.3.0 '@storybook/addon-docs': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(@types/react@18.3.14)(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-essentials': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(@types/react@18.3.14)(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-interactions': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-links': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-styling-webpack': - specifier: catalog:storybook + specifier: ^1.0.0 version: 1.0.1(storybook@8.4.7(prettier@3.4.2))(webpack@5.97.1) '@storybook/addon-webpack5-compiler-babel': - specifier: catalog:storybook + specifier: ^3.0.3 version: 3.0.3(webpack@5.97.1) '@storybook/blocks': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) '@storybook/react-webpack5': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(@swc/core@1.10.0(@swc/helpers@0.5.15))(esbuild@0.24.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)(webpack-cli@5.1.4) '@storybook/test': - specifier: catalog:storybook + specifier: ^8.2.8 version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) '@tailwindcss/typography': - specifier: catalog:tailwind + specifier: ^0.5.13 version: 0.5.15(tailwindcss@3.4.16(ts-node@10.9.2(@swc/core@1.10.0(@swc/helpers@0.5.15))(@types/node@22.10.1)(typescript@5.7.2))) '@testing-library/cypress': - specifier: catalog:test + specifier: ^10.0.2 version: 10.0.2(cypress@13.16.1) '@testing-library/jest-dom': - specifier: catalog:test + specifier: ^6.4.6 version: 6.6.3 '@testing-library/react': - specifier: catalog:test + specifier: ^16.0.0 version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/user-event': - specifier: catalog:test + specifier: ^14.5.2 version: 14.5.2(@testing-library/dom@10.4.0) '@types/jest': - specifier: catalog:test + specifier: ^29.5.12 version: 29.5.14 '@types/js-cookie': - specifier: 'catalog:' + specifier: ^3.0.6 version: 3.0.6 '@types/luxon': - specifier: 'catalog:' + specifier: ^3.4.2 version: 3.4.2 '@types/react': - specifier: catalog:react18 + specifier: ^18.3.3 version: 18.3.14 '@types/react-dom': - specifier: catalog:react18 + specifier: ^18.3.0 version: 18.3.2 '@types/react-relay': - specifier: catalog:graphql + specifier: ^16.0.6 version: 16.0.6 '@types/relay-runtime': - specifier: catalog:graphql + specifier: ^17.0.3 version: 17.0.4 '@types/relay-test-utils': - specifier: catalog:graphql + specifier: ^14.1.4 version: 14.1.4 autoprefixer: - specifier: catalog:tailwind + specifier: ^10.4.19 version: 10.4.20(postcss@8.4.49) babel-jest: - specifier: catalog:test + specifier: ^29.7.0 version: 29.7.0(@babel/core@7.26.0) babel-loader: - specifier: catalog:storybook + specifier: ^9.1.3 version: 9.2.1(@babel/core@7.26.0)(webpack@5.97.1) babel-plugin-relay: - specifier: catalog:graphql + specifier: ^17.0.0 version: 17.0.0 css-loader: - specifier: catalog:storybook + specifier: ^7.1.2 version: 7.1.2(webpack@5.97.1) cypress: - specifier: catalog:test + specifier: ^13.13.3 version: 13.16.1 cypress-plugin-steps: - specifier: catalog:test + specifier: ^1.1.1 version: 1.1.1(cypress@13.16.1) cypress-wait-until: - specifier: catalog:test + specifier: ^3.0.2 version: 3.0.2 dotenv: specifier: ^16.4.5 @@ -10215,7 +10209,7 @@ snapshots: '@babel/generator@7.17.7': dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.26.3 jsesc: 2.5.2 source-map: 0.5.7 From 63da69959dcc6318fd2a8868aa605e73dc3a3ee1 Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Tue, 3 Dec 2024 20:27:00 -0300 Subject: [PATCH 06/12] Revert "Temporarily remove catalogs to use GitHub version" This reverts commit b805e7ff533c860a988efafe63a15012a7d52c54. --- packages/components/package.json | 108 ++++++++++++++--------------- pnpm-lock.yaml | 114 ++++++++++++++++--------------- 2 files changed, 114 insertions(+), 108 deletions(-) diff --git a/packages/components/package.json b/packages/components/package.json index 3977213f..aa36d124 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -21,74 +21,74 @@ "test:unit": "jest --config ./jest.config.ts" }, "dependencies": { - "@hookform/resolvers": "^3.6.0", - "@mui/lab": "^5.0.0-alpha.170", - "@mui/material": "^5.15.19", - "@mui/system": "^5.15.19", - "@storybook/react": "^8.2.8", - "@tanstack/react-query": "^5.45.1", + "@hookform/resolvers": "catalog:", + "@mui/lab": "catalog:material-ui", + "@mui/material": "catalog:material-ui", + "@mui/system": "catalog:material-ui", + "@storybook/react": "catalog:storybook", + "@tanstack/react-query": "catalog:", "framer-motion": "^11.5.4", - "graphql": "^16.8.1", - "js-cookie": "^3.0.5", - "luxon": "^3.4.4", - "next": "14.3.0-canary.24", - "react-hook-form": "^7.51.5", - "react-relay": "^16.2.0", - "react-virtuoso": "^4.7.11", - "relay-runtime": "^16.2.0", + "graphql": "catalog:graphql", + "js-cookie": "catalog:", + "luxon": "catalog:", + "next": "catalog:", + "react-hook-form": "catalog:", + "react-relay": "catalog:graphql", + "react-virtuoso": "catalog:", + "relay-runtime": "catalog:graphql", "slugify": "^1.6.6", "use-long-press": "^3.2.0", - "zod": "^3.23.8", - "zustand": "^4.5.2" + "zod": "catalog:", + "zustand": "catalog:" }, "peerDependencies": { "@baseapp-frontend/authentication": "workspace:*", "@baseapp-frontend/design-system": "workspace:*", "@baseapp-frontend/graphql": "workspace:*", "@baseapp-frontend/utils": "workspace:*", - "react": "18.3.1", - "react-dom": "18.3.1" + "react": "catalog:react18", + "react-dom": "catalog:react18" }, "devDependencies": { - "@babel/preset-env": "^7.24.7", - "@babel/preset-react": "^7.24.7", - "@babel/preset-typescript": "^7.24.7", + "@babel/preset-env": "catalog:storybook", + "@babel/preset-react": "catalog:storybook", + "@babel/preset-typescript": "catalog:storybook", "@baseapp-frontend/config": "workspace:*", "@baseapp-frontend/test": "workspace:*", "@baseapp-frontend/tsconfig": "workspace:*", - "@chromatic-com/storybook": "^1.5.0", - "@cypress/webpack-dev-server": "^3.10.1", - "@faker-js/faker": "^9.0.3", - "@storybook/addon-docs": "^8.2.8", - "@storybook/addon-essentials": "^8.2.8", - "@storybook/addon-interactions": "^8.2.8", - "@storybook/addon-links": "^8.2.8", - "@storybook/addon-styling-webpack": "^1.0.0", - "@storybook/addon-webpack5-compiler-babel": "^3.0.3", - "@storybook/blocks": "^8.2.8", - "@storybook/react-webpack5": "^8.2.8", - "@storybook/test": "^8.2.8", - "@tailwindcss/typography": "^0.5.13", - "@testing-library/cypress": "^10.0.2", - "@testing-library/jest-dom": "^6.4.6", - "@testing-library/react": "^16.0.0", - "@testing-library/user-event": "^14.5.2", - "@types/jest": "^29.5.12", - "@types/js-cookie": "^3.0.6", - "@types/luxon": "^3.4.2", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@types/react-relay": "^16.0.6", - "@types/relay-runtime": "^17.0.3", - "@types/relay-test-utils": "^14.1.4", - "autoprefixer": "^10.4.19", - "babel-jest": "^29.7.0", - "babel-loader": "^9.1.3", - "babel-plugin-relay": "^17.0.0", - "css-loader": "^7.1.2", - "cypress": "^13.13.3", - "cypress-plugin-steps": "^1.1.1", - "cypress-wait-until": "^3.0.2", + "@chromatic-com/storybook": "catalog:storybook", + "@cypress/webpack-dev-server": "catalog:test", + "@faker-js/faker": "catalog:test", + "@storybook/addon-docs": "catalog:storybook", + "@storybook/addon-essentials": "catalog:storybook", + "@storybook/addon-interactions": "catalog:storybook", + "@storybook/addon-links": "catalog:storybook", + "@storybook/addon-styling-webpack": "catalog:storybook", + "@storybook/addon-webpack5-compiler-babel": "catalog:storybook", + "@storybook/blocks": "catalog:storybook", + "@storybook/react-webpack5": "catalog:storybook", + "@storybook/test": "catalog:storybook", + "@tailwindcss/typography": "catalog:tailwind", + "@testing-library/cypress": "catalog:test", + "@testing-library/jest-dom": "catalog:test", + "@testing-library/react": "catalog:test", + "@testing-library/user-event": "catalog:test", + "@types/jest": "catalog:test", + "@types/js-cookie": "catalog:", + "@types/luxon": "catalog:", + "@types/react": "catalog:react18", + "@types/react-dom": "catalog:react18", + "@types/react-relay": "catalog:graphql", + "@types/relay-runtime": "catalog:graphql", + "@types/relay-test-utils": "catalog:graphql", + "autoprefixer": "catalog:tailwind", + "babel-jest": "catalog:test", + "babel-loader": "catalog:storybook", + "babel-plugin-relay": "catalog:graphql", + "css-loader": "catalog:storybook", + "cypress": "catalog:test", + "cypress-plugin-steps": "catalog:test", + "cypress-wait-until": "catalog:test", "dotenv": "^16.4.5", "dotenv-cli": "^7.4.2", "eslint-plugin-storybook": "catalog:lint", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c402ae86..a4f314e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,6 +48,9 @@ catalogs: react-hook-form: specifier: ^7.51.5 version: 7.53.2 + react-virtuoso: + specifier: ^4.7.11 + version: 4.12.3 typescript: specifier: ^5.4.5 version: 5.7.2 @@ -316,6 +319,9 @@ catalogs: cypress-plugin-steps: specifier: ^1.1.1 version: 1.1.1 + cypress-wait-until: + specifier: ^3.0.2 + version: 3.0.2 jest: specifier: ^29.7.0 version: 29.7.0 @@ -467,55 +473,55 @@ importers: specifier: workspace:* version: link:../utils '@hookform/resolvers': - specifier: ^3.6.0 + specifier: 'catalog:' version: 3.9.1(react-hook-form@7.53.2(react@18.3.1)) '@mui/lab': - specifier: ^5.0.0-alpha.170 + specifier: catalog:material-ui version: 5.0.0-alpha.174(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@mui/material@5.16.9(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/material': - specifier: ^5.15.19 + specifier: catalog:material-ui version: 5.16.9(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@mui/system': - specifier: ^5.15.19 + specifier: catalog:material-ui version: 5.16.8(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@emotion/styled@11.13.5(@emotion/react@11.13.5(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1))(@types/react@18.3.14)(react@18.3.1) '@storybook/react': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2) '@tanstack/react-query': - specifier: ^5.45.1 + specifier: 'catalog:' version: 5.62.3(react@18.3.1) framer-motion: specifier: ^11.5.4 version: 11.13.1(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) graphql: - specifier: ^16.8.1 + specifier: catalog:graphql version: 16.9.0 js-cookie: - specifier: ^3.0.5 + specifier: 'catalog:' version: 3.0.5 luxon: - specifier: ^3.4.4 + specifier: 'catalog:' version: 3.5.0 next: - specifier: 14.3.0-canary.24 + specifier: 'catalog:' version: 14.3.0-canary.24(@babel/core@7.26.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: - specifier: 18.3.1 + specifier: catalog:react18 version: 18.3.1 react-dom: - specifier: 18.3.1 + specifier: catalog:react18 version: 18.3.1(react@18.3.1) react-hook-form: - specifier: ^7.51.5 + specifier: 'catalog:' version: 7.53.2(react@18.3.1) react-relay: - specifier: ^16.2.0 + specifier: catalog:graphql version: 16.2.0(react@18.3.1) react-virtuoso: - specifier: ^4.7.11 + specifier: 'catalog:' version: 4.12.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) relay-runtime: - specifier: ^16.2.0 + specifier: catalog:graphql version: 16.2.0 slugify: specifier: ^1.6.6 @@ -524,20 +530,20 @@ importers: specifier: ^3.2.0 version: 3.2.0(react@18.3.1) zod: - specifier: ^3.23.8 + specifier: 'catalog:' version: 3.23.8 zustand: - specifier: ^4.5.2 + specifier: 'catalog:' version: 4.5.5(@types/react@18.3.14)(react@18.3.1) devDependencies: '@babel/preset-env': - specifier: ^7.24.7 + specifier: catalog:storybook version: 7.26.0(@babel/core@7.26.0) '@babel/preset-react': - specifier: ^7.24.7 + specifier: catalog:storybook version: 7.26.3(@babel/core@7.26.0) '@babel/preset-typescript': - specifier: ^7.24.7 + specifier: catalog:storybook version: 7.26.0(@babel/core@7.26.0) '@baseapp-frontend/config': specifier: workspace:* @@ -549,103 +555,103 @@ importers: specifier: workspace:* version: link:../tsconfig '@chromatic-com/storybook': - specifier: ^1.5.0 + specifier: catalog:storybook version: 1.9.0(react@18.3.1) '@cypress/webpack-dev-server': - specifier: ^3.10.1 + specifier: catalog:test version: 3.11.0(webpack-cli@5.1.4)(webpack@5.97.1) '@faker-js/faker': - specifier: ^9.0.3 + specifier: catalog:test version: 9.3.0 '@storybook/addon-docs': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(@types/react@18.3.14)(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-essentials': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(@types/react@18.3.14)(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-interactions': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-links': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) '@storybook/addon-styling-webpack': - specifier: ^1.0.0 + specifier: catalog:storybook version: 1.0.1(storybook@8.4.7(prettier@3.4.2))(webpack@5.97.1) '@storybook/addon-webpack5-compiler-babel': - specifier: ^3.0.3 + specifier: catalog:storybook version: 3.0.3(webpack@5.97.1) '@storybook/blocks': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2)) '@storybook/react-webpack5': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(@storybook/test@8.4.7(storybook@8.4.7(prettier@3.4.2)))(@swc/core@1.10.0(@swc/helpers@0.5.15))(esbuild@0.24.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.7(prettier@3.4.2))(typescript@5.7.2)(webpack-cli@5.1.4) '@storybook/test': - specifier: ^8.2.8 + specifier: catalog:storybook version: 8.4.7(storybook@8.4.7(prettier@3.4.2)) '@tailwindcss/typography': - specifier: ^0.5.13 + specifier: catalog:tailwind version: 0.5.15(tailwindcss@3.4.16(ts-node@10.9.2(@swc/core@1.10.0(@swc/helpers@0.5.15))(@types/node@22.10.1)(typescript@5.7.2))) '@testing-library/cypress': - specifier: ^10.0.2 + specifier: catalog:test version: 10.0.2(cypress@13.16.1) '@testing-library/jest-dom': - specifier: ^6.4.6 + specifier: catalog:test version: 6.6.3 '@testing-library/react': - specifier: ^16.0.0 + specifier: catalog:test version: 16.1.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/user-event': - specifier: ^14.5.2 + specifier: catalog:test version: 14.5.2(@testing-library/dom@10.4.0) '@types/jest': - specifier: ^29.5.12 + specifier: catalog:test version: 29.5.14 '@types/js-cookie': - specifier: ^3.0.6 + specifier: 'catalog:' version: 3.0.6 '@types/luxon': - specifier: ^3.4.2 + specifier: 'catalog:' version: 3.4.2 '@types/react': - specifier: ^18.3.3 + specifier: catalog:react18 version: 18.3.14 '@types/react-dom': - specifier: ^18.3.0 + specifier: catalog:react18 version: 18.3.2 '@types/react-relay': - specifier: ^16.0.6 + specifier: catalog:graphql version: 16.0.6 '@types/relay-runtime': - specifier: ^17.0.3 + specifier: catalog:graphql version: 17.0.4 '@types/relay-test-utils': - specifier: ^14.1.4 + specifier: catalog:graphql version: 14.1.4 autoprefixer: - specifier: ^10.4.19 + specifier: catalog:tailwind version: 10.4.20(postcss@8.4.49) babel-jest: - specifier: ^29.7.0 + specifier: catalog:test version: 29.7.0(@babel/core@7.26.0) babel-loader: - specifier: ^9.1.3 + specifier: catalog:storybook version: 9.2.1(@babel/core@7.26.0)(webpack@5.97.1) babel-plugin-relay: - specifier: ^17.0.0 + specifier: catalog:graphql version: 17.0.0 css-loader: - specifier: ^7.1.2 + specifier: catalog:storybook version: 7.1.2(webpack@5.97.1) cypress: - specifier: ^13.13.3 + specifier: catalog:test version: 13.16.1 cypress-plugin-steps: - specifier: ^1.1.1 + specifier: catalog:test version: 1.1.1(cypress@13.16.1) cypress-wait-until: - specifier: ^3.0.2 + specifier: catalog:test version: 3.0.2 dotenv: specifier: ^16.4.5 From dccddc10e3af259b82df3298423dbc60f3215cdf Mon Sep 17 00:00:00 2001 From: Priscilla de Roode Date: Wed, 4 Dec 2024 19:16:10 -0300 Subject: [PATCH 07/12] BA-1832: fixes --- .../AddProfileMenuItem/types.ts | 2 +- .../AddProfileModal/constants.ts | 15 +++ .../ProfilePopover/AddProfileModal/index.tsx | 111 ++++++++---------- .../ProfilePopover/AddProfileModal/styled.tsx | 9 ++ .../ProfilePopover/AddProfileModal/types.ts | 14 +++ 5 files changed, 87 insertions(+), 64 deletions(-) create mode 100644 packages/components/modules/profiles/ProfilePopover/AddProfileModal/constants.ts create mode 100644 packages/components/modules/profiles/ProfilePopover/AddProfileModal/styled.tsx create mode 100644 packages/components/modules/profiles/ProfilePopover/AddProfileModal/types.ts diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts index 5d43a747..c6a758a7 100644 --- a/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileMenuItem/types.ts @@ -1,6 +1,6 @@ import { FC } from 'react' -import { AddProfileModalProps } from '../AddProfileModal' +import { AddProfileModalProps } from '../AddProfileModal/types' export interface AddProfileMenuItemProps { addNewProfileLabel?: string diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/constants.ts b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/constants.ts new file mode 100644 index 00000000..6cc0463d --- /dev/null +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/constants.ts @@ -0,0 +1,15 @@ +import z from 'zod' + +const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/ + +export const schema = z.object({ + name: z + .string() + .trim() + .min(3, { message: 'Must have at least three character' }) + .max(255, { message: 'Must have at most 255 characters' }), + urlPath: z + .string() + .regex(slugRegex, 'Must contain only lowercase letters, numbers, and hyphens') + .max(500, { message: 'Must have at most 500 characters' }), +}) diff --git a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx index 4a8678a0..3241225c 100644 --- a/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx +++ b/packages/components/modules/profiles/ProfilePopover/AddProfileModal/index.tsx @@ -1,58 +1,32 @@ import { FC } from 'react' -import { TextField } from '@baseapp-frontend/design-system' +import { CloseIcon, TextField } from '@baseapp-frontend/design-system' import { setFormRelayErrors } from '@baseapp-frontend/utils' import { zodResolver } from '@hookform/resolvers/zod' import { LoadingButton } from '@mui/lab' import { + Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, + IconButton, Link, Typography, } from '@mui/material' import { useForm } from 'react-hook-form' import { ConnectionHandler } from 'react-relay' import slugify from 'slugify' -import z from 'zod' -import { Form } from '../../../__shared__/SocialInput/styled' import { useOrganizationCreateMutation } from '../../graphql/mutations/OrganizationCreate' - -const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/ - -const schema = z.object({ - name: z - .string() - .trim() - .min(3, { message: 'Must have at least three character' }) - .max(255, { message: 'Must have at most 255 characters' }), - urlPath: z - .string() - .regex(slugRegex, 'Must contain only lowercase letters, numbers, and hyphens') - .max(500, { message: 'Must have at most 500 characters' }), -}) +import { schema } from './constants' +import { Form } from './styled' +import { AddProfileModalProps, OrganizationCreateForm } from './types' let nextClientMutationId = 0 -export interface AddProfileModalProps { - addNewProfileLabel?: string - termsAndConditionsUrl?: string - addNewProfileDescription?: string - onClose?: () => void - open: boolean - setOpen: (open: boolean) => void - submitLabel?: string -} - -interface OrganizationCreateForm { - name: string - urlPath: string -} - const AddProfileModal: FC = ({ addNewProfileLabel = 'New organization', termsAndConditionsUrl = '', @@ -97,9 +71,7 @@ const AddProfileModal: FC = ({ if (!payload) { return } - const newEdge = payload.getLinkedRecord('profile') - const root = store.getRoot() const meRecord = root?.getLinkedRecord('me') @@ -153,41 +125,54 @@ const AddProfileModal: FC = ({ }, }} > - {addNewProfileLabel} - + + + {addNewProfileLabel} + + + + + + {addNewProfileDescription} - { - form.trigger('name') - }} - onBlur={() => { - if (!form.getValues('urlPath')) { - form.setValue('urlPath', slugify(form.getValues('name').toLocaleLowerCase())) + + { + form.trigger('name') + }} + onBlur={() => { + if (!form.getValues('urlPath')) { + form.setValue('urlPath', slugify(form.getValues('name').toLocaleLowerCase())) + form.trigger('urlPath') + } + }} + /> + { form.trigger('urlPath') - } - }} - /> - { - form.trigger('urlPath') - }} - /> - - Upon confirming, you agree to our{' '} - - Terms and Conditions. - - + }} + /> + + Upon confirming, you agree to our{' '} + + Terms and Conditions. + + +