[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/docs/README.md from the organizations VTEX app.

[Assistant]
Here's the implementation:

```markdown
# Organizations

This application allows you to create organization and manage users under that organization with diffrent roles.

## Usage

Install this app in your workspace

```js
vtex install vtex.organizations@1.x
```

> ### Link application to development workspace
> - clone the application to your working environment and checkout to the correct branch (i.e: `dev-master`)
> - link this app to your workspace (`vtex link --verbose`)

## Prerequisites

In order to run this application following master data schemas and indices should be created.
Use `MASTER DATA API - V2` in vtex api documentation to create those schemas (https://developers.vtex.com/reference#master-data-api-v2-overview)

These schemas are shared among several applications `vtex.admin-organizations`, `vtex.auth-challenge` and `vtex.organizations`, therefore if you have already created these schemas and indices you can ignore this step

### Master data schemas

<details><summary>BusinessPermission</summary>

```

Data Entity Name: BusinessPermission
Schema Name: business-permission-schema-v1

{
	"properties": {
		"name": {
			"type": "string"
		},
		"label": {
			"type": "string"
		}
	},
	"v-default-fields": [
		"name",
		"label",
		"id"
	],
	"required": [
		"name"
	],
	"v-indexed": [
		"name"
	],
	"v-security": {
		"allowGetAll": true,
		"publicRead": [
			"name",
			"label",
			"id"
		],
		"publicWrite": [
			"name",
			"label"
		],
		"publicFilter": [
			"name",
			"id"
		]
	}
}

```
</details>

<details><summary>BusinessRole</summary>

```

Data Entity Name: BusinessRole
Schema Name: business-role-schema-v1

{
	"properties": {
		"name": {
			"type": "string"
		},
		"label": {
			"type": "string"
		},
		"permissions": {
			"type": "string"
		}
	},
	"definitions": {
		"permission": {
			"type": "string"
		}
	},
	"v-default-fields": [
		"name",
		"label",
		"id",
		"permissions"
	],
	"required": [
		"name"
	],
	"v-indexed": [
		"name"
	],
	"v-security": {
		"allowGetAll": true,
		"publicRead": [
			"name",
			"label",
			"permissions",
			"id"
		],
		"publicWrite": [
			"name",
			"label",
			"permissions"
		],
		"publicFilter": [
			"name",
			"id"
		]
	}
}

```
</details>

<details><summary>BusinessOrganization</summary>

```

Data Entity Name: BusinessOrganization
Schema Name: business-organization-schema-v1

{
	"properties": {
		"name": {
			"type": "string"
		},
		"telephone": {
			"type": "string"
		},
		"address": {
			"type": "string"
		},
		"email": {
			"type": "string"
		}
	},
	"v-default-fields": [
		"name",
		"telephone",
		"id",
		"address",
		"email"
	],
	"required": [
		"name",
		"telephone"
	],
	"v-indexed": [
		"name",
		"telephone",
		"email"
	],
	"v-security": {
		"allowGetAll": true,
		"publicRead": [
			"name",
			"telephone",
			"id",
			"address",
			"email"
		],
		"publicWrite": [
			"name",
			"telephone",
			"address",
			"email"
		],
		"publicFilter": [
			"name",
			"telephone",
			"id",
			"email"
		]
	}
}

```
</details>

<details><summary>UserOrganization</summary>

```

Data Entity Name: UserOrganization
Schema Name: user-organization-schema-v1

{
	"properties": {
		"email": {
			"type": "string"
		},
		"businessOrganizationId": {
			"type": "string",
			"link": "http://api.vtex.com/{{accountName}}/dataentities/BusinessOrganization/schemas/business-organization-schema-v1"
		},
		"roleId": {
			"type": "string",
			"link": "http://api.vtex.com/{{accountName}}/dataentities/BusinessRole/schemas/business-role-schema-v1"
		},
		"status": {
			"type": "string"
		}
	},
	"v-default-fields": [
		"email",
		"id",
		"businessOrganizationId",
		"roleId",
		"status"
	],
	"required": [
		"email",
		"businessOrganizationId",
		"roleId",
		"status"
	],
	"v-indexed": [
		"email",
		"businessOrganizationId",
		"roleId",
		"status"
	],
	"v-security": {
		"allowGetAll": true,
		"publicRead": [
			"email",
			"id",
			"businessOrganizationId",
			"businessOrganizationId_linked",
			"roleId",
			"roleId_linked",
			"status"
		],
		"publicWrite": [
			"id",
			"email",
			"businessOrganizationId",
			"roleId",
			"status"
		],
		"publicFilter": [
			"email",
			"id",
			"businessOrganizationId",
			"roleId",
			"status"
		]
	},
	"v-triggers": [
		{
			"name": "organization-assignment-accept-email",
			"active": true,
			"condition": "status=APPROVED",
			"action": {
				"type": "email",
				"provider": "default",
				"subject": "Organization Assignment Acceptance",
				"to": [
					"{!email}"
				],
				"replyTo": "noreply@company.com",
				"body": "You have been assigned to {!businessOrganizationId_linked.name}."
			}
		},
		{
			"name": "organization-assignment-decline-email",
			"active": true,
			"condition": "status=DECLINED",
			"action": {
				"type": "email",
				"provider": "default",
				"subject": "Organization Assignment Decline",
				"to": [
					"{!email}"
				],
				"replyTo": "noreply@company.com",
				"body": "You have left the organization {!businessOrganizationId_linked.name}."
			}
		}
	]
}

```
</details>

### Changes to existing **CL** table
We need to add two fields to existing **CL** master data table.
```
isOrgAdmin: Boolean
organizationId: VarChar 100
```
After creating the fields change settings of that fields with edit field feature.
You can update the field settings as shown in the image below.

<a href="https://drive.google.com/uc?export=view&id=1IzMTKBpB4A9snERILSQJ-DQd1Zp758wE">View Image</a>

>**_NOTE:_** **isOrgAdmin** field should check following checkboxes
> **Make readable without credential**,
> **Is searchable**,
> **Is filterable**,

> **organizationId** field should check following checkboxes
> **Is nullable**,
> **Make readable without credential**,
> **Allow editing without credential**,
> **Allow filter without credential**,
> **Is searchable**,
> **Is filterable**,

Dont forget to `save` and `reindex` `CL` table once you add all the fields.

### [Deprecated] removed master data collections and schemas
>Data Entity Name: **Persona**, Schema Name: **persona-schema-v1**

>Data Entity Name: **OrgAssignment**, Schema Name: **organization-assignment-schema-v1**

## Important

> **_NOTE:_**  create `Manager` role with required permissions using `vtex.admin-organizations` application (https://github.com/vtex/admin-organizations)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/my-organization.css from the organizations VTEX app.

[Assistant]
Here's the implementation:

```css
.reloadMessage >div>div>div>div:nth-child(2){
  width: 100%;
}

.collapsibleWrapper > div > div:first-child{
  margin-right: 8px;
}

.listItemBlock{
  height: 160px;
}

.detailSummaryColumn{
  width: 32%;
  height: 180px;
}
```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/MyOrganizationLink.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import { FC } from 'react'
import { injectIntl } from 'react-intl'

interface RenderProps {
  name: string
  path: string
}

interface Props {
  render: (paths: RenderProps[]) => any
  intl: any
}

const MyOrganizationLink: FC<Props> = ({ render, intl }: Props) => {
  return render([
    {
      name: intl.formatMessage({ id: 'store/my-organization.link' }),
      path: '/myorganization',
    },
  ])
}

export default injectIntl(MyOrganizationLink)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/MyOrganizationPage.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Route } from 'react-router-dom'
import { ToastProvider } from 'vtex.styleguide'
import MyOrganization from './components/MyOrganization'

const MyOrganizationPage = () => {
  return (
    <ToastProvider positioning="window">
      <Route
        path="/myorganization"
        exact
        component={() => <MyOrganization />}
      />
    </ToastProvider>
  )
}

export default MyOrganizationPage

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/BlockContent.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC } from 'react'
import { useCssHandles } from 'vtex.css-handles'

const CSS_HANDLES = ['challengeContentWrapper'] as const

const BlockContent: FC<ChallengeProps> = ({ children }: ChallengeProps) => {
  const handles = useCssHandles(CSS_HANDLES)
  return (
    <div className={`mw9 center ${handles.challengeContentWrapper}`}>
      {children}
    </div>
  )
}

export default BlockContent

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/package.json from the organizations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "scripts": {
    "lint": "tsc --noEmit && eslint --quiet --fix --ext ts,tsx .",
    "test": "vtex-test-tools test"
  },
  "dependencies": {
    "apollo-client": "^2.6.3",
    "classnames": "^2.2.6",
    "graphql": "^14.5.8",
    "graphql-tag": "^2.10.3",
    "ramda": "^0.26.1",
    "react": "^16.8.6",
    "react-apollo": "^3.1.3",
    "react-dom": "^16.8.6",
    "react-intl": "3.9.1",
    "react-router-dom": "^4.3.1"
  },
  "devDependencies": {
    "@types/classnames": "^2.2.9",
    "@types/graphql": "^14.5.0",
    "@types/jest": "^24.0.21",
    "@types/node": "^12.12.3",
    "@types/ramda": "^0.26.33",
    "@types/react": "^16.8.22",
    "@types/react-intl": "^2.3.18",
    "@types/react-router-dom": "^4.3.1",
    "@vtex/test-tools": "^0.3.2",
    "@vtex/tsconfig": "^0.2.0",
    "eslint": "5.x",
    "eslint-config-vtex-react": "^5.0.1",
    "prettier": "^1.18.2",
    "prop-types": "^15.7.2",
    "typescript": "3.9.7"
  },
  "version": "1.9.0"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/store/interfaces.json from the organizations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "my-account-link.my-organizations-link": {
    "component": "MyOrganizationLink"
  },
  "my-account-link.my-organizations-page": {
    "component": "MyOrganizationPage"
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/store/plugins.json from the organizations VTEX app.

[Assistant]
Here's the implementation:

```json
{
  "my-account-menu > my-account-link": "my-account-link.my-organizations-link",
  "my-account-pages > my-account-page": "my-account-link.my-organizations-page"
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/typings/vtex.my-account-commons.d.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.my-account-commons' {
  import React from 'react'

  interface ComponentProps {
    titleId: string
    namespace: string
  }

  export const ContentWrapper: React.SFC<ComponentProps>
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/typings/globals.d.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { ReactNode } from 'react'
import { ApolloError } from 'apollo-client'

declare global {
  interface ChallengeProps {
    children: ReactNode[]
  }

  interface MDField {
    key: string
    value: string
  }

  interface MDSearchResult {
    loading: boolean
    error?: ApolloError
    data: MDSearchData
  }

  interface MDSearchData {
    documents: MDSearchDocumentResult[]
  }

  interface MDSearchDocumentResult {
    id: string
    fields: MDField[]
  }

  interface StorefrontFunctionComponent<P = {}> extends FunctionComponent<P> {
    schema?: object
    getSchema?(props?: P): object
  }

  interface Role {
    value: string
    label: string
    name: string
  }

  interface BusinessOrganization {
    name: string
    telephone: string
    id: string
    address?: string
    email?: string
  }

  interface OrganizationAssignment {
    id: string
    email?: string
    budgetAmount?: string
    roleId?: string
    status?: string
    roleId_linked?: Role
    businessOrganizationId_linked?: BusinessOrganization
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/typings/vtex.render-runtime.d.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
/* Typings for `render-runtime` */
declare module 'vtex.render-runtime' {
  import { Component, ComponentType, ReactElement, ReactType } from 'react'

  export interface NavigationOptions {
    page: string
    params?: any
  }

  export interface RenderContextProps {
    runtime: {
      navigate: (options: NavigationOptions) => void
    }
  }

  interface ExtensionPointProps {
    id: string
    [key: string]: any
  }

  interface ChildBlock<BlockProps> {
    props: BlockProps
  }

  export const ExtensionPoint: ComponentType<ExtensionPointProps>
  export const useChildBlock: <BlockProps>({
    id,
  }: {
    id: string
  }) => ChildBlock<BlockProps> | null
  export const Helmet: ReactElement
  export const Link: ReactType
  export const NoSSR: ReactElement
  export const RenderContextConsumer: any
  export const TreePathContextConsumer: any
  export const useTreePath: any
  export const useRuntime: any
  export const canUseDOM: boolean
  export const withRuntimeContext: <TOriginalProps extends {}>(
    Component: ComponentType<TOriginalProps & RenderContextProps>
  ) => ComponentType<TOriginalProps>

  export const withSession: <TOriginalProps extends {}>(
    Component: ComponentType<TOriginalProps & RenderContextProps>
  ) => ComponentType<TOriginalProps>

  interface KeyValue {
    value: string
  }

  interface Session {
    id: string
    namespaces: {
      profile: {
        isAuthenticated: KeyValue
      }
    }
  }

  interface SessionUnauthorized {
    type: 'Unauthorized'
    message: string
  }

  export interface RenderSession {
    sessionPromise: Promise<SessionPromise>
  }

  export interface SessionPromise {
    response: Session | SessionUnauthorized
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/typings/css.d.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.css' {
  const css: any
  export default css
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/typings/graphql.d.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module '*.graphql' {
  import { DocumentNode } from 'graphql'

  const value: DocumentNode
  export default value
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/typings/vtex.styleguide.d.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
declare module 'vtex.styleguide' {
  import { ComponentType } from 'react'
  export const Button: ComponentType<InputProps>
  export const Dropdown: ComponentType<InputProps>
  export const Input: ComponentType<InputProps>
  export const Table: ComponentType<InputProps>
  export const EmptyState: ComponentType<InputProps>
  export const PageHeader: ComponentType<InputProps>
  export const Layout: ComponentType<InputProps>
  export const PageBlock: ComponentType<InputProps>
  export const Divider: ComponentType<InputProps>
  export const ButtonWithIcon: ComponentType<InputProps>
  export const IconCheck: ComponentType<InputProps>
  export const Modal: ComponentType<InputProps>
  export const ModalDialog: ComponentType<InputProps>
  export const Alert: ComponentType<InputProps>
  export const ToastProvider: ComponentType<InputProps>
  export const ToastConsumer: ComponentType<InputProps>
  export const Spinner: ComponentType<InputProps>
  export const Tag: ComponentType<InputProps>
  export const Collapsible: ComponentType<InputProps>
  export const Checkbox: ComponentType<InputProps>

  interface InputProps {
    [key: string]: any
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/utils/const.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const CLIENT_ACRONYM = 'CL'
export const CLIENT_FIELDS = [
  'id',
  'email',
  'budgetAmount',
  'approved',
  'isOrgAdmin',
  'organizationId',
]
export const PROFILE_FIELDS = 'isOrgAdmin,organizationId'

export const BUSINESS_ROLE = 'BusinessRole'
export const BUSINESS_ROLE_FIELDS = ['id', 'name', 'label']
export const BUSINESS_ROLE_SCHEMA = 'business-role-schema-v1'

export const ORG_ASSIGNMENT = 'UserOrganization'
export const ORG_ASSIGNMENT_FIELDS = [
  'id',
  'email',
  'budgetAmount',
  'businessOrganizationId',
  'businessOrganizationId_linked',
  'status',
  'roleId',
  'roleId_linked',
]
export const ORG_ASSIGNMENT_SCHEMA = 'user-organization-schema-v1'

export const BUSINESS_ORGANIZATION = 'BusinessOrganization'
export const BUSINESS_ORGANIZATION_FIELDS = [
  'id',
  'name',
  'telephone',
  'address',
  'email',
]
export const BUSINESS_ORGANIZATION_SCHEMA = 'business-organization-schema-v1'

export const ORG_ASSIGNMENT_STATUS_APPROVED = 'APPROVED'

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/utils/documentSerializer.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { endsWith } from 'ramda'

export const documentSerializer = (documents: any) => {
  if (!documents) {
    return []
  }

  const fieldReducer = (fieldsAccumulator: any, field: any) => {
    if (!endsWith('_linked', field.key)) {
      fieldsAccumulator[field.key] = field.value
    }
    if (endsWith('_linked', field.key)) {
      fieldsAccumulator[field.key] = JSON.parse(field.value)
    }
    return fieldsAccumulator
  }

  const documentReducer = (documentAccumulator: any, document: any) => {
    if (!document || !document.fields) {
      return documentAccumulator
    }
    documentAccumulator.push(document.fields.reduce(fieldReducer, {}))
    return documentAccumulator
  }

  return documents.reduce(documentReducer, [])
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/utils/textUtil.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
export const addressSplitter = (address: string) => {
  if (address === undefined || address.trim() === '') {
    return []
  }

  return address.split(',')
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/utils/graphqlErrorHandler.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { pathOr } from 'ramda'

export const getErrorMessage = (e: any) => {
  const message = pathOr(
    '',
    [
      'graphQLErrors',
      0,
      'extensions',
      'exception',
      'response',
      'data',
      'Message',
    ],
    e
  )
  return message
}

export const handleGlobalError = () => {
  return (e: Error) => {
    var message: string = pathOr(
      '',
      [
        'graphQLErrors',
        0,
        'extensions',
        'exception',
        'response',
        'data',
        'Message',
      ],
      e
    )

    if (message == '') {
      message = pathOr(
        '',
        [
          'graphQLErrors',
          0,
          'extensions',
          'exception',
          'response',
          'data',
          'errors',
          0,
          'errors',
          0,
          'Message',
        ],
        e
      )
    }

    return Promise.reject(message)
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/utils/cacheUtils.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
import GET_DOCUMENT from '../graphql/documents.graphql'
import profileQuery from '../graphql/getProfile.graphql'
import { pathOr, find, propEq, reject } from 'ramda'
import {
  CLIENT_ACRONYM,
  CLIENT_FIELDS,
  PROFILE_FIELDS,
  ORG_ASSIGNMENT,
  ORG_ASSIGNMENT_FIELDS,
  ORG_ASSIGNMENT_SCHEMA,
} from './const'

const compareEmailFields = (a: any, b: any) => {
  const emailA = a.fields.find(({ key }: { key: string }) => key === 'email')
  const emailB = b.fields.find(({ key }: { key: string }) => key === 'email')
  return emailA.value.localeCompare(emailB.value)
}

const userListArgs = (orgId: string) => {
  return {
    query: GET_DOCUMENT,
    variables: {
      acronym: ORG_ASSIGNMENT,
      fields: ORG_ASSIGNMENT_FIELDS,
      where: `businessOrganizationId=${orgId}`,
      schema: ORG_ASSIGNMENT_SCHEMA,
      page: 1,
      pageSize: 100,
      sort: 'email ASC',
    },
  }
}

const getProfile = () => {
  return {
    query: profileQuery,
    variables: { customFields: PROFILE_FIELDS },
  }
}

const clientListArgs = (email: string) => {
  return {
    query: GET_DOCUMENT,
    variables: {
      acronym: CLIENT_ACRONYM,
      fields: CLIENT_FIELDS,
      where: `email=${email}`,
    },
  }
}

export const updateCacheClient = (
  cache: any,
  data: any,
  email: string,
  budgetAmount: string,
  organizationId: string,
  isOrgAdmin: string
) => {
  try {
    const response: any = cache.readQuery(clientListArgs(email))
    const id = pathOr(
      pathOr('', ['updateMyDocument', 'cacheId'], data),
      ['createMyDocument', 'cacheId'],
      data
    )
    let fields = pathOr([], ['myDocuments', 0, 'fields'], response)

    fields = reject(propEq('key', 'organizationId'), fields) as any
    fields = reject(propEq('key', 'isOrgAdmin'), fields) as any
    fields = reject(propEq('key', 'email'), fields) as any
    fields = reject(propEq('key', 'budgetAmount'), fields) as any
    fields = reject(propEq('key', 'approved'), fields) as any

    const newFields = [
      ...fields,
      ...[
        { key: 'organizationId', value: organizationId, __typename: 'Field' },
        { key: 'isOrgAdmin', value: isOrgAdmin, __typename: 'Field' },
        { key: 'email', value: email, __typename: 'Field' },
        { key: 'budgetAmount', value: budgetAmount, __typename: 'Field' },
        { key: 'approved', value: 'true', __typename: 'Field' },
      ],
    ]

    response.myDocuments = [
      { id: id, fields: newFields, __typename: 'Document' },
    ]
    const writeData = {
      ...clientListArgs(email),
      data: { myDocuments: response.myDocuments },
    }
    cache.writeQuery(writeData)
  } catch (e) {
    // continue regardless of error
  }
}

export const updateCacheAddUser = (
  cache: any,
  data: any,
  roles: Role[],
  organizationId: string,
  email: string,
  budgetAmount: string,
  roleId: string
) => {
  try {
    const response: any = cache.readQuery(userListArgs(organizationId))

    const org = pathOr(
      '',
      ['value'],
      find(
        propEq('key', 'businessOrganizationId_linked'),
        pathOr([], ['myDocuments', 0, 'fields'], response)
      )
    )
    const selectedRole = find(propEq('value', roleId), roles)
    const id = pathOr(
      pathOr('', ['updateMyDocument', 'cacheId'], data),
      ['createMyDocument', 'cacheId'],
      data
    )
    const assignmentFields = [
      { key: 'id', value: id, __typename: 'Field' },
      {
        key: 'businessOrganizationId',
        value: organizationId,
        __typename: 'Field',
      },
      {
        key: 'email',
        value: email,
        __typename: 'Field',
      },
      {
        key: 'budgetAmount',
        value: budgetAmount,
        __typename: 'Field',
      },
      {
        key: 'roleId',
        value: roleId,
        __typename: 'Field',
      },
      { key: 'businessOrganizationId_linked', value: org, __typename: 'Field' },
      {
        key: 'roleId_linked',
        value: selectedRole
          ? JSON.stringify({
              name: selectedRole.name,
              label: selectedRole.label,
              id: selectedRole.value,
            })
          : '',
        __typename: 'Field',
      },
    ]

    const newData = [
      ...response.myDocuments,
      { id: id, fields: assignmentFields, __typename: 'Document' },
    ].sort(compareEmailFields)
    const writeData = {
      ...userListArgs(organizationId),
      data: { myDocuments: newData },
    }
    cache.writeQuery(writeData)
  } catch (e) {
    // continue regardless of error
  }
}

export const updateCacheEditUser = (
  cache: any,
  data: any,
  roles: Role[],
  organizationId: string,
  roleId: string
) => {
  try {
    const response: any = cache.readQuery(userListArgs(organizationId))
    const selectedRole = find(propEq('value', roleId), roles)
    const id = pathOr(
      pathOr('', ['createMyDocument', 'cacheId'], data),
      ['updateMyDocument', 'cacheId'],
      data
    )

    const fields = pathOr(
      [],
      ['fields'],
      find(propEq('id', id), pathOr([], ['myDocuments'], response))
    )
    const fieldsExceptRoleAndRoleIdLinked = reject(
      propEq('key', 'roleId'),
      reject(propEq('key', 'roleId_linked'), fields)
    )

    fieldsExceptRoleAndRoleIdLinked.push({
      key: 'roleId_linked',
      value: selectedRole
        ? JSON.stringify({
            name: selectedRole.name,
            label: selectedRole.label,
            id: selectedRole.value,
          })
        : '',
      __typename: 'Field',
    })
    fieldsExceptRoleAndRoleIdLinked.push({
      key: 'roleId',
      value: roleId,
      __typename: 'Field',
    })

    const newData = pathOr([], ['myDocuments'], response).map((x: any) => {
      if (x.id === id) {
        x.fields = fieldsExceptRoleAndRoleIdLinked
      }
      return x
    })
    const writeData = {
      ...userListArgs(organizationId),
      data: { myDocuments: newData },
    }
    cache.writeQuery(writeData)
  } catch (e) {
    // continue regardless of error
  }
}

export const updateCacheDeleteUser = (
  cache: any,
  data: any,
  organizationId: string
) => {
  try {
    const id = pathOr('', ['deleteMyDocument', 'cacheId'], data)
    const response: any = cache.readQuery(userListArgs(organizationId))

    const newData = reject(propEq('id', id), response.myDocuments)

    const writeData = {
      ...userListArgs(organizationId),
      data: { myDocuments: newData },
    }

    cache.writeQuery(writeData)
  } catch (e) {
    // continue regardless of error
  }
}

export const updateCacheProfile = (cache: any, organizationId: string) => {
  try {
    const response: any = cache.readQuery(getProfile())

    const customFieldsExceptOrgId = reject(
      propEq('key', 'organizationId'),
      response.profile.customFields
    )

    const customFields = [
      ...customFieldsExceptOrgId,
      {
        key: 'organizationId',
        value: organizationId,
        __typename: 'ProfileCustomField',
      },
    ]

    response.profile.customFields = customFields

    const writeData = {
      ...getProfile(),
      data: { profile: response.profile },
    }

    cache.writeQuery(writeData)
  } catch (e) {
    // continue regardless of error
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/AddOrganization.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState, useReducer } from 'react'
import { pathOr, isEmpty, filter, propEq, reject, find, last } from 'ramda'
import { PageBlock, Input, Button } from 'vtex.styleguide'
import { useMutation, useQuery } from 'react-apollo'
import { injectIntl } from 'react-intl'

import CREATE_DOCUMENT from '../graphql/createDocument.graphql'
import GET_DOCUMENT from '../graphql/documents.graphql'
import UPDATE_DOCUMENT from '../graphql/updateDocument.graphql'

import {
  BUSINESS_ROLE,
  BUSINESS_ROLE_FIELDS,
  BUSINESS_ROLE_SCHEMA,
  ORG_ASSIGNMENT,
  ORG_ASSIGNMENT_SCHEMA,
  BUSINESS_ORGANIZATION,
  BUSINESS_ORGANIZATION_SCHEMA,
  CLIENT_ACRONYM,
  ORG_ASSIGNMENT_STATUS_APPROVED,
} from '../utils/const'
import { handleGlobalError } from '../utils/graphqlErrorHandler'
import { updateCacheProfile } from '../utils/cacheUtils'

interface Props {
  userEmail: string
  clientId: string
  updateOrgInfo: () => void
  showToast: (message: any) => void
  intl: any
}

interface ErrorMessage {
  name: string
  isError: boolean
  message: string
}

interface ErrorState {
  errorMessages: ErrorMessage[]
}

type Action<K, V = void> = V extends void ? { type: K } : { type: K } & V

type Actions =
  | Action<'NAME_ERROR', { args: { name: string } }>
  | Action<'TELEPHONE_ERROR', { args: { telephone: string } }>
  | Action<'EMAIL_ERROR', { args: { email: string } }>

const AddOrganization = ({
  userEmail,
  clientId,
  intl,
  updateOrgInfo,
  showToast,
}: Props) => {
  const initialState = {
    errorMessages: [] as ErrorMessage[],
  }

  const reducer = (state: ErrorState, action: Actions): ErrorState => {
    switch (action.type) {
      case 'NAME_ERROR': {
        const isErrorN = isEmpty(action.args.name)
        const messageN = isErrorN ? 'Name is required' : ''
        const _errorN: ErrorMessage = {
          ...pathOr(
            [],
            [0],
            filter(propEq('name', 'NAME_ERROR'), state.errorMessages)
          ),
          ...{ name: 'NAME_ERROR', isError: isErrorN, message: messageN },
        }
        return {
          ...state,
          ...{
            errorMessages: [
              ...reject(propEq('name', 'NAME_ERROR'), state.errorMessages),
              ...[_errorN],
            ],
          },
        }
      }
      case 'TELEPHONE_ERROR': {
        const isErrorT = isEmpty(action.args.telephone)
        const messageT = isErrorT ? 'Telephone is required' : ''
        const _errorT: ErrorMessage = {
          ...pathOr(
            [],
            [0],
            filter(propEq('name', 'TELEPHONE_ERROR'), state.errorMessages)
          ),
          ...{ name: 'TELEPHONE_ERROR', isError: isErrorT, message: messageT },
        }
        return {
          ...state,
          ...{
            errorMessages: [
              ...reject(propEq('name', 'TELEPHONE_ERROR'), state.errorMessages),
              ...[_errorT],
            ],
          },
        }
      }
      case 'EMAIL_ERROR': {
        let isErrorE = false
        let messageE = ''
        if (
          !isEmpty(action.args.email) &&
          !/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(action.args.email)
        ) {
          isErrorE = true
        }

        messageE = isErrorE ? 'Email is incorrect' : ''
        const _errorE: ErrorMessage = {
          ...pathOr(
            [],
            [0],
            filter(propEq('name', 'EMAIL_ERROR'), state.errorMessages)
          ),
          ...{ name: 'EMAIL_ERROR', isError: isErrorE, message: messageE },
        }
        return {
          ...state,
          ...{
            errorMessages: [
              ...reject(propEq('name', 'EMAIL_ERROR'), state.errorMessages),
              ...[_errorE],
            ],
          },
        }
      }
      default:
        return state
    }
  }

  const [state, dispatch] = useReducer(reducer, initialState)

  const [name, setName] = useState('')
  const [telephone, setTelephone] = useState('')
  const [address, setAddress] = useState('')
  const [email, setEmail] = useState('')

  const [createDocument] = useMutation(CREATE_DOCUMENT)
  const [updateDocument] = useMutation(UPDATE_DOCUMENT)

  const getOrganizationFields = () => {
    return [
      { key: 'name', value: name },
      { key: 'telephone', value: telephone },
      { key: 'address', value: address },
      { key: 'email', value: email },
    ]
  }

  const getOrganizationAssignmentFields = (
    organizationId: string,
    roleId: string
  ) => {
    return [
      { key: 'email', value: userEmail },
      { key: 'businessOrganizationId', value: organizationId },
      { key: 'roleId', value: roleId },
      { key: 'status', value: ORG_ASSIGNMENT_STATUS_APPROVED },
    ]
  }

  const createOrganization = async (roleId: string) => {
    let orgId = ''
    createDocument({
      variables: {
        acronym: BUSINESS_ORGANIZATION,
        document: { fields: getOrganizationFields() },
        schema: BUSINESS_ORGANIZATION_SCHEMA,
      },
    })
      .then((organizationResponse: any) => {
        orgId = pathOr(
          '',
          ['data', 'createMyDocument', 'cacheId'],
          organizationResponse
        )

        return createDocument({
          variables: {
            acronym: ORG_ASSIGNMENT,
            document: {
              fields: getOrganizationAssignmentFields(orgId, roleId),
            },
            schema: ORG_ASSIGNMENT_SCHEMA,
          },
        })
      })
      .then(() => {
        return updateDocument({
          variables: {
            acronym: CLIENT_ACRONYM,
            document: {
              fields: [
                { key: 'id', value: clientId },
                { key: 'organizationId', value: orgId },
              ],
            },
          },
          update: (cache: any) => updateCacheProfile(cache, orgId),
        })
      })

      .catch(handleGlobalError())
      .then(() => {
        setName('')
        setTelephone('')
        setAddress('')
        setEmail('')
        updateOrgInfo()
      })
      .catch((message: string) => {
        showToast({
          message: `${intl.formatMessage({
            id: 'store/my-organization.toast.organization.create.error',
          })} "${message}"`,
          duration: 5000,
          horizontalPosition: 'right',
        })
      })
  }

  const { data: roleData } = useQuery(GET_DOCUMENT, {
    variables: {
      acronym: BUSINESS_ROLE,
      fields: BUSINESS_ROLE_FIELDS,
      where: '(name=*manager*)',
      schema: BUSINESS_ROLE_SCHEMA,
    },
  })

  const roleFields = roleData
    ? pathOr([], ['fields'], last(roleData.myDocuments))
    : []

  const roleId =
    roleFields && roleFields.length > 0
      ? pathOr('', ['value'], find(propEq('key', 'id'), roleFields))
      : ''

  return (
    <PageBlock>
      <div className="mb5">
        <Input
          placeholder={intl.formatMessage({
            id: 'store/my-organization.input.placeholder.organizationName',
          })}
          label={intl.formatMessage({
            id: 'store/my-organization.input.label.organizationName',
          })}
          value={name}
          error={pathOr(
            false,
            [0, 'isError'],
            filter(propEq('name', 'NAME_ERROR'), state.errorMessages)
          )}
          errorMessage={pathOr(
            '',
            [0, 'message'],
            filter(propEq('name', 'NAME_ERROR'), state.errorMessages)
          )}
          onChange={(e: any) => {
            setName(e.target.value)
            dispatch({ type: 'NAME_ERROR', args: { name: e.target.value } })
          }}
        />
      </div>
      <div className="mb5">
        <Input
          placeholder={intl.formatMessage({
            id: 'store/my-organization.input.placeholder.telephone',
          })}
          label={intl.formatMessage({
            id: 'store/my-organization.input.label.telephone',
          })}
          value={telephone}
          error={pathOr(
            false,
            [0, 'isError'],
            filter(propEq('name', 'TELEPHONE_ERROR'), state.errorMessages)
          )}
          errorMessage={pathOr(
            '',
            [0, 'message'],
            filter(propEq('name', 'TELEPHONE_ERROR'), state.errorMessages)
          )}
          onChange={(e: any) => {
            setTelephone(e.target.value)
            dispatch({
              type: 'TELEPHONE_ERROR',
              args: { telephone: e.target.value },
            })
          }}
        />
      </div>
      <div className="mb5">
        <Input
          placeholder={intl.formatMessage({
            id: 'store/my-organization.input.placeholder.address',
          })}
          label={intl.formatMessage({
            id: 'store/my-organization.input.label.address',
          })}
          value={address}
          onChange={(e: any) => setAddress(e.target.value)}
        />
      </div>
      <div className="mb5">
        <Input
          placeholder={intl.formatMessage({
            id: 'store/my-organization.input.placeholder.email',
          })}
          label={intl.formatMessage({
            id: 'store/my-organization.input.label.email',
          })}
          value={email}
          error={pathOr(
            false,
            [0, 'isError'],
            filter(propEq('name', 'EMAIL_ERROR'), state.errorMessages)
          )}
          errorMessage={pathOr(
            '',
            [0, 'message'],
            filter(propEq('name', 'EMAIL_ERROR'), state.errorMessages)
          )}
          onChange={(e: any) => {
            setEmail(e.target.value)
            dispatch({ type: 'EMAIL_ERROR', args: { email: e.target.value } })
          }}
        />
      </div>

      <div className="mb5">
        <Button
          variation="primary"
          disabled={
            name === '' ||
            telephone === '' ||
            (email !== '' &&
              pathOr(
                true,
                [0, 'isError'],
                filter(propEq('name', 'EMAIL_ERROR'), state.errorMessages)
              ))
          }
          onClick={() => createOrganization(roleId)}>
          {intl.formatMessage({ id: 'store/my-organization.button.save' })}
        </Button>
      </div>
    </PageBlock>
  )
}

export default injectIntl(AddOrganization)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/UserListItem.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import { pathOr } from 'ramda'
import { useQuery } from 'react-apollo'
import DOCUMENTS from '../graphql/documents.graphql'
import { CLIENT_ACRONYM, CLIENT_FIELDS } from '../utils/const'
import { Collapsible, Tag, Button } from 'vtex.styleguide'
import { documentSerializer } from '../utils/documentSerializer'

import { injectIntl } from 'react-intl'

import styles from '../my-organization.css'

interface Props {
  isCurrentUserAdmin: boolean
  isDefaultAssignment: boolean
  orgAssignment: OrganizationAssignment
  intl: any
  edit: (assignmentId: string) => void
  deleteAssignment: (assignmentId: string) => void
}

const UserListItem = ({
  isCurrentUserAdmin,
  isDefaultAssignment,
  orgAssignment,
  edit,
  deleteAssignment,
  intl,
}: Props) => {
  const { data, loading } = useQuery(DOCUMENTS, {
    variables: {
      acronym: CLIENT_ACRONYM,
      fields: CLIENT_FIELDS,
      where: `email=${orgAssignment.email}`,
    },
  })

  const client = pathOr(
    {},
    [0],
    documentSerializer(pathOr([], ['myDocuments'], data))
  ) as any

  const isAdminUserListItem: boolean = ((pathOr(
    'false',
    ['isOrgAdmin'],
    client
  ) as string) === 'true') as boolean

  const isApprovedUser: boolean = ((pathOr(
    'false',
    ['approved'],
    client
  ) as string) === 'true') as boolean

  const [isOpen, setIsOpen] = useState(false)

  const userContent = () => {
    return (
      <div
        key={`item-sub-key-${orgAssignment.id}`}
        className="flex center ph3-ns pa2">
        <div className="flex-row w-100  cf ph2-ns">
          <div className="fl w-60 pa2">
            <div className="pt2 f6">
              <span>
                {intl.formatMessage({
                  id: 'store/my-organization.my-user.table-title.email',
                })}
              </span>
            </div>
            <div className="pt3 b">
              <span>{orgAssignment.email}</span>
            </div>
          </div>
          <div className="fl w-20 pa2">
            <div className="pt2 f6">
              <span>
                {intl.formatMessage({
                  id: 'store/my-organization.my-user.table-title.role',
                })}
              </span>
            </div>
            <div className="pt3 b">
              <span>
                {pathOr('', ['roleId_linked', 'label'], orgAssignment)}
              </span>
            </div>
          </div>
          <div className="fl w-20 pa2">
            <div className="pt2 f6">
              <span>
                {intl.formatMessage({
                  id: 'store/my-organization.my-user.table-title.status',
                })}
              </span>
            </div>
            <div className="pt3">
              <span>
                {isApprovedUser ? (
                  <Tag type="success" variation="low">
                    {intl.formatMessage({
                      id:
                        'store/my-organization.my-organization.status.approved',
                    })}
                  </Tag>
                ) : (
                  <Tag type="warning" variation="low">
                    {intl.formatMessage({
                      id:
                        'store/my-organization.my-organization.status.not-approved',
                    })}
                  </Tag>
                )}
              </span>
            </div>
          </div>
        </div>
      </div>
    )
  }

  const toggleOpen = () => {
    setIsOpen(!isOpen)
  }

  return loading ? (
    <div key="loading-" />
  ) : (
    <div
      id={`item-${orgAssignment.id}`}
      key={`item-key-${orgAssignment.id}`}
      className={`${styles.collapsibleWrapper} bg-muted-5 ma3 ba b--black-10`}>
      <Collapsible
        header={userContent()}
        onClick={toggleOpen}
        isOpen={isOpen}
        align="right"
        caretColor="muted">
        <div className="center bg-white bt b--black-10 pt3">
          <div className="flex cf ph2-ns">
            <div className="flex-column fl w-70 pa5 f6">
              <span>
                {isAdminUserListItem && (
                  <Tag type="success" variation="low">
                    {intl.formatMessage({
                      id:
                        'store/my-organization.my-organization.status.isOrgAdmin',
                    })}
                  </Tag>
                )}
              </span>
            </div>
            <div className="flex-column fl w-30">
              {!isDefaultAssignment &&
              (isCurrentUserAdmin || !isAdminUserListItem) ? (
                <div className="pt5 pb5 pr3">
                  <div className="pa2 w-100">
                    <Button
                      variation="tertiary"
                      size="small"
                      onClick={() => edit(orgAssignment.id)}
                      block>
                      {intl.formatMessage({
                        id: 'store/my-organization.my-user.table-title.edit',
                      })}
                    </Button>
                  </div>
                  <div className="pa2 w-100">
                    <Button
                      variation="danger-tertiary"
                      size="small"
                      onClick={() => deleteAssignment(orgAssignment.id)}
                      block>
                      {intl.formatMessage({
                        id: 'store/my-organization.my-user.table-title.delete',
                      })}
                    </Button>
                  </div>
                </div>
              ) : (
                <div />
              )}
            </div>
          </div>
        </div>
      </Collapsible>
    </div>
  )
}

export default injectIntl(UserListItem)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/MyOrganization.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useEffect, useState, useRef, useCallback } from 'react'
import { useQuery, useApolloClient } from 'react-apollo'
import { Alert, ToastConsumer, Button, Spinner, Tag } from 'vtex.styleguide'
import { injectIntl } from 'react-intl'
import { pathOr, find, propEq, equals } from 'ramda'

import { ContentWrapper } from 'vtex.my-account-commons'

import MyUsers from './MyUsers'
import AddOrganization from './AddOrganization'
import DefaultAssignmentInfo from './DefaultAssignmentInfo'

import DOCUMENTS from '../graphql/documents.graphql'
import profileQuery from '../graphql/getProfile.graphql'

import { documentSerializer } from '../utils/documentSerializer'
import {
  PROFILE_FIELDS,
  BUSINESS_ROLE,
  BUSINESS_ROLE_FIELDS,
  BUSINESS_ROLE_SCHEMA,
  ORG_ASSIGNMENT,
  ORG_ASSIGNMENT_FIELDS,
  ORG_ASSIGNMENT_SCHEMA,
  CLIENT_ACRONYM,
  CLIENT_FIELDS,
  ORG_ASSIGNMENT_STATUS_APPROVED,
} from '../utils/const'
import styles from '../my-organization.css'

interface Props {
  intl: any
}

const MyOrganization = ({ intl }: Props) => {
  // my organization state
  const [clientId, setClientId] = useState('')
  const [organizationId, setOrganizationId] = useState('')
  const [email, setEmail] = useState('')
  const [isOrgAdmin, setIsOrgAdmin] = useState(false)
  const [defaultOrgAssignment, setDefaultOrgAssignment] = useState(
    ({} as any) as OrganizationAssignment
  )
  const [userRole, setUserRole] = useState(({} as any) as Role)
  const [loading, setLoading] = useState(false)
  const [reloadStart, setReloadStart] = useState(false)
  const [showOrganizationReload, setShowOrganizationReload] = useState(false)

  // apollo client
  const client = useApolloClient()

  // restrict re render multiple times
  const afterEmailSet = useRef(false)
  const afterFirstLoad = useRef(false)

  // get initial profile info
  const { data: profileData, loading: profileLoading } = useQuery(
    profileQuery,
    { variables: { customFields: PROFILE_FIELDS } }
  )

  // Load data
  const load = useCallback(() => {
    let organizationIdData = ''
    let orgAssignmentsData = ([] as any) as OrganizationAssignment[]
    let defaultAssignmentData = ({} as any) as OrganizationAssignment
    let userRoleData = ({} as any) as Role

    setReloadStart(true)

    // Get client info
    return client
      .query({
        query: DOCUMENTS,
        variables: {
          acronym: CLIENT_ACRONYM,
          fields: CLIENT_FIELDS,
          where: `email=${email}`,
        },
        fetchPolicy: 'no-cache',
      })
      .then(({ data }: any) => {
        const clients = documentSerializer(data ? data.myDocuments : [])

        organizationIdData = pathOr('', [0, 'organizationId'], clients)

        // get current user organization assignments
        return client
          .query({
            query: DOCUMENTS,
            variables: {
              acronym: ORG_ASSIGNMENT,
              schema: ORG_ASSIGNMENT_SCHEMA,
              fields: ORG_ASSIGNMENT_FIELDS,
              where: `email=${email}`,
            },
            fetchPolicy: 'no-cache',
          })
          .catch(() => {
            return Promise.resolve({ myDocuments: [] })
          })
      })

      .then(({ data }: any) => {
        if (data) {
          const assignments = documentSerializer(data ? data.myDocuments : [])

          const defaultAssignment: OrganizationAssignment = find(
            propEq('businessOrganizationId', organizationIdData)
          )(assignments)

          defaultAssignmentData = defaultAssignment
            ? defaultAssignment
            : (({} as any) as OrganizationAssignment)
        }

        // get current organization's users assignments
        return client
          .query({
            query: DOCUMENTS,
            variables: {
              acronym: ORG_ASSIGNMENT,
              schema: ORG_ASSIGNMENT_SCHEMA,
              fields: ORG_ASSIGNMENT_FIELDS,
              where: `(businessOrganizationId=${organizationIdData} AND status=${ORG_ASSIGNMENT_STATUS_APPROVED})`,
            },
            fetchPolicy: 'no-cache',
          })
          .catch(() => {
            return Promise.resolve({ myDocuments: [] })
          })
      })
      .then(({ data }: any) => {
        if (data) {
          orgAssignmentsData = documentSerializer(data ? data.myDocuments : [])
        }

        // get roles in the system
        return client.query({
          query: DOCUMENTS,
          variables: {
            acronym: BUSINESS_ROLE,
            schema: BUSINESS_ROLE_SCHEMA,
            fields: BUSINESS_ROLE_FIELDS,
          },
          fetchPolicy: 'no-cache',
        })
      })
      .then(({ data }: any) => {
        if (data) {
          const rolesList = documentSerializer(data ? data.myDocuments : [])
          const roleId = pathOr('', ['roleId'], defaultAssignmentData)
          userRoleData =
            roleId !== '' ? find(propEq('id', roleId))(rolesList) : {}

          setReloadStart(false)
        }
        return Promise.resolve({
          organizationIdData,
          orgAssignmentsData,
          defaultAssignmentData,
          userRoleData,
        })
      })
  }, [client, email])

  // update state variables
  const updateState = (data: any) => {
    setOrganizationId(data.organizationIdData)
    setDefaultOrgAssignment(data.defaultAssignmentData)
    setUserRole(data.userRoleData)
  }

  // after email changed
  useEffect(() => {
    const abortController = new AbortController()
    if (afterEmailSet.current && !afterFirstLoad.current) {
      afterFirstLoad.current = true

      setLoading(true)
      load().then((data: any) => {
        updateState(data)
        setLoading(false)
      })
    }
    return () => {
      setLoading(false)
      abortController.abort()
    }
  }, [email, load])

  // after profile data loaded
  useEffect(() => {
    const abortController = new AbortController()

    const idData = pathOr('', ['profile', 'id'], profileData)
    const emailData = pathOr('', ['profile', 'email'], profileData)
    const isOrgAdminData = pathOr(
      'false',
      ['value'],
      find(propEq('key', 'isOrgAdmin'))(
        pathOr([], ['profile', 'customFields'], profileData)
      )
    ) as any
    const organizationIdData = pathOr(
      '',
      ['value'],
      find(propEq('key', 'organizationId'))(
        pathOr([], ['profile', 'customFields'], profileData)
      )
    ) as any

    if (emailData !== '') {
      setClientId(idData)
      setEmail(emailData)
      setIsOrgAdmin(isOrgAdminData === 'true' || isOrgAdminData === true)
      setOrganizationId(organizationIdData)
    }

    if (emailData !== '' && !afterFirstLoad.current) {
      afterEmailSet.current = true
    }

    return () => {
      abortController.abort()
    }
  }, [profileData])

  // Continue reload - [Leave, Delete] default organization
  const infoUpdatedDefaultAssignment = () => {
    setShowOrganizationReload(true)
    load().then((data: any) => {
      if (
        data &&
        equals(
          data.organizationIdData,
          '' && equals(data.defaultAssignmentData, {})
        )
      ) {
        updateState(data)
        setShowOrganizationReload(false)
      } else {
        infoUpdatedDefaultAssignment()
      }
    })
  }

  // Continue reload - [Create] organization
  const infoUpdatedCreateOrganization = () => {
    setShowOrganizationReload(true)
    load().then((data: any) => {
      const isValidDefaultAssignment =
        find(propEq('email', email))(
          pathOr([], ['orgAssignmentsData'], data)
        ) !== undefined
      if (
        data &&
        !equals(data.organizationIdData, '') &&
        !equals(data.defaultAssignmentData, {}) &&
        isValidDefaultAssignment
      ) {
        updateState(data)
        setShowOrganizationReload(false)
      } else {
        infoUpdatedCreateOrganization()
      }
    })
  }

  const closeReloadMessage = () => {
    setShowOrganizationReload(false)
  }

  const getHeaderContent = () => {
    return isOrgAdmin ? (
      <span className="mr4">
        <Tag type="success" variation="low">
          {intl.formatMessage({
            id: 'store/my-organization.my-organization.status.isOrgAdmin',
          })}
        </Tag>
      </span>
    ) : (
      <span />
    )
  }

  const headerConfig = () => {
    return {
      namespace: 'vtex-account__my_organization',
      titleId: 'store/my-organization.my-organization.organization.title',
      headerContent: getHeaderContent(),
    }
  }

  return (
    <ContentWrapper {...headerConfig()}>
      {() => (
        <ToastConsumer>
          {({ showToast }: any) =>
            loading || profileLoading ? (
              <Spinner />
            ) : (
              <div className="pl5 pl7-ns near-black">
                {showOrganizationReload && (
                  <div className={`${styles.reloadMessage} mb5`}>
                    <Alert type="warning" onClose={closeReloadMessage}>
                      <div className="flex-row w-100">
                        {' '}
                        <div className="fl flex-grow-1 justify-start w-90">
                          {intl.formatMessage({
                            id:
                              'store/my-organization.my-organization.reload-message',
                          })}
                        </div>
                        <div className="fl flex-grow-1 justify-end w-10">
                          <Button
                            variation="secondary"
                            size="small"
                            isLoading={reloadStart}>
                            Reload
                          </Button>
                        </div>
                      </div>
                    </Alert>
                  </div>
                )}
                {(organizationId == '' || organizationId === 'null') &&
                  (isOrgAdmin ? (
                    <div className="mb5 mt5">
                      <h2 className="">
                        {intl.formatMessage({
                          id:
                            'store/my-organization.my-organization.create-new-organization',
                        })}
                      </h2>

                      <AddOrganization
                        userEmail={email}
                        clientId={clientId}
                        updateOrgInfo={infoUpdatedCreateOrganization}
                        showToast={showToast}
                      />
                    </div>
                  ) : (
                    <div className="flex flex-column items-center">
                      <span className="c-on-base">
                        {intl.formatMessage({
                          id:
                            'store/my-organization.my-organization.not-yet-assigned-1',
                        })}
                      </span>
                      <span className="c-on-base">
                        {intl.formatMessage({
                          id:
                            'store/my-organization.my-organization.not-yet-assigned-2',
                        })}
                      </span>
                    </div>
                  ))}
                {defaultOrgAssignment && defaultOrgAssignment.id && (
                  <div className="ba b--light-gray">
                    <DefaultAssignmentInfo
                      clientId={clientId}
                      defaultAssignment={defaultOrgAssignment}
                      userRole={userRole}
                      infoUpdated={infoUpdatedDefaultAssignment}
                      showToast={showToast}
                      isOrgAdmin={isOrgAdmin}
                    />

                    {((userRole &&
                      userRole.name &&
                      userRole.name === 'manager') ||
                      isOrgAdmin) && (
                      <MyUsers
                        isCurrentUserAdmin={isOrgAdmin}
                        organizationId={organizationId}
                        email={email}
                        showToast={showToast}
                      />
                    )}
                  </div>
                )}
              </div>
            )
          }
        </ToastConsumer>
      )}
    </ContentWrapper>
  )
}

export default React.memo(injectIntl(MyOrganization))

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/MyUsers.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import { useQuery, useMutation, useApolloClient } from 'react-apollo'
import { Button } from 'vtex.styleguide'
import { pathOr, find, propEq } from 'ramda'
import { injectIntl } from 'react-intl'
import { Input } from 'vtex.styleguide'

import { documentSerializer } from '../utils/documentSerializer'

import AddUser from './modals/AddUser'
import UserConfirmationModal from './modals/UserConfirmationModal'
import UserEditModal from './modals/UserEditModal'

import documentQuery from '../graphql/documents.graphql'
import DELETE_DOCUMENT from '../graphql/deleteDocument.graphql'
import UPDATE_DOCUMENT from '../graphql/updateDocument.graphql'
import UserListItem from './UserListItem'

import { updateCacheDeleteUser } from '../utils/cacheUtils'
import {
  CLIENT_ACRONYM,
  CLIENT_FIELDS,
  BUSINESS_ROLE,
  BUSINESS_ROLE_FIELDS,
  BUSINESS_ROLE_SCHEMA,
  ORG_ASSIGNMENT,
  ORG_ASSIGNMENT_FIELDS,
  ORG_ASSIGNMENT_SCHEMA,
} from '../utils/const'
import { getErrorMessage } from '../utils/graphqlErrorHandler'

interface Props {
  isCurrentUserAdmin: boolean
  email: string
  organizationId: string
  showToast: (message: any) => void
  intl: any
}

const MyUsers = ({
  isCurrentUserAdmin,
  organizationId,
  email,
  showToast,
  intl,
}: Props) => {
  const PAGE_SIZE_STEPPER = 100
  const [searchUser, setSearchUser] = useState('')
  const [updateDocument] = useMutation(UPDATE_DOCUMENT)
  const [deleteDocument] = useMutation(DELETE_DOCUMENT, {
    update: (cache: any, { data }: any) =>
      updateCacheDeleteUser(cache, data, organizationId),
  })

  const [isAddNewUserOpen, setIsAddNewUserOpen] = useState(false)

  const [isDeleteConfirmationOpen, setIsDeleteConfirmationOpen] = useState(
    false
  )

  const [deleteConfirmationLoading, setDeleteConfirmationLoading] = useState(
    false
  )

  const [sharedOrgAssignment, setSharedOrgAssignment] = useState(
    ({} as any) as OrganizationAssignment
  )

  const client = useApolloClient()

  const [isUserEditOpen, setIsUserEditOpen] = useState(false)

  const { data: roleData } = useQuery(documentQuery, {
    variables: {
      acronym: BUSINESS_ROLE,
      fields: BUSINESS_ROLE_FIELDS,
      schema: BUSINESS_ROLE_SCHEMA,
    },
  })
  const { data: orgAssignments } = useQuery(documentQuery, {
    skip: organizationId == '',
    variables: {
      acronym: ORG_ASSIGNMENT,
      fields: ORG_ASSIGNMENT_FIELDS,
      where: `businessOrganizationId=${organizationId}`,
      schema: ORG_ASSIGNMENT_SCHEMA,
      page: 1,
      pageSize: PAGE_SIZE_STEPPER,
      sort: 'email ASC',
    },
  })

  const { data: defaultAssignmentData } = useQuery(documentQuery, {
    skip: organizationId == '',
    variables: {
      acronym: ORG_ASSIGNMENT,
      fields: ORG_ASSIGNMENT_FIELDS,
      where: `businessOrganizationId=${organizationId} AND email=${email}`,
      schema: ORG_ASSIGNMENT_SCHEMA,
    },
  })

  const rolesList: any[] = documentSerializer(
    pathOr([], ['myDocuments'], roleData)
  )
  const roles: Role[] = rolesList.map((role: any) => ({
    label: role.label,
    value: role.id,
    name: role.name,
  }))

  const assignments: OrganizationAssignment[] = documentSerializer(
    pathOr([], ['myDocuments'], orgAssignments)
  )

  const defaultAssignment: OrganizationAssignment[] = documentSerializer(
    pathOr([], ['myDocuments'], defaultAssignmentData)
  )

  const defaultUserAssignment = find(
    propEq('email', email),
    defaultAssignment
  ) as OrganizationAssignment

  const deleteOrgAssignment = (assignment: OrganizationAssignment) => {
    return deleteDocument({
      variables: {
        acronym: ORG_ASSIGNMENT,
        documentId: assignment.id,
      },
    })
  }

  // ** Delete Org Assignment
  // ** Remove `organizationId` from CL
  // ** Remove `isOrgAdmin` from CL
  const deleteAssignmentWithUser = (assignment: OrganizationAssignment) => {
    return deleteOrgAssignment(assignment)
      .then(() => {
        return client.query({
          query: documentQuery,
          variables: {
            acronym: CLIENT_ACRONYM,
            fields: CLIENT_FIELDS,
            where: `email=${assignment.email}`,
          },
        })
      })
      .then(({ data }: any) => {
        const clid = pathOr('', ['myDocuments', 0, 'id'], data)
        return updateDocument({
          variables: {
            acronym: CLIENT_ACRONYM,
            document: {
              fields: [
                { key: 'id', value: clid },
                { key: 'organizationId', value: '' },
                { key: 'isOrgAdmin', value: 'false' },
                { key: 'approved', value: 'false' },
              ],
            },
          },
        })
      })
  }

  // Delete user - [Delete Btn clicked]
  const deleteUserAssignment = (assignmentId: string) => {
    const assignment = find(propEq('id', assignmentId), assignments)
    setSharedOrgAssignment(assignment as OrganizationAssignment)
    setIsDeleteConfirmationOpen(true)
  }

  // Confirm delete - [Confirm delete btn clicked]
  // ** delete org assignment with user if request is approved
  const confirmDelete = () => {
    setDeleteConfirmationLoading(true)
    deleteAssignmentWithUser(sharedOrgAssignment)
      .then(() => {
        setDeleteConfirmationLoading(false)
        setIsDeleteConfirmationOpen(false)
        setSharedOrgAssignment(({} as any) as OrganizationAssignment)
      })
      .catch((e: Error) => {
        const message = getErrorMessage(e)
        setDeleteConfirmationLoading(false)
        setIsDeleteConfirmationOpen(false)
        setSharedOrgAssignment(({} as any) as OrganizationAssignment)
        showToast({
          message: `${intl.formatMessage({
            id: 'store/my-organization.toast.user.delete.error',
          })} ${message}`,
          duration: 5000,
          horizontalPosition: 'right',
        })
      })
  }

  // Close delete confirmation
  const closeDelete = () => {
    setIsDeleteConfirmationOpen(false)
    setSharedOrgAssignment(({} as any) as OrganizationAssignment)
  }

  // Edit organization assignment - [Edit Btn clicked]
  const editUser = (assignmentId: string) => {
    const assignment = find(propEq('id', assignmentId), assignments)
    setSharedOrgAssignment(assignment as OrganizationAssignment)
    setIsUserEditOpen(true)
  }

  // Close edit organization assignment
  const closeUserEditModal = () => {
    setSharedOrgAssignment(({} as any) as OrganizationAssignment)
    setIsUserEditOpen(false)
  }

  // Create organization assignment - [New organization Btn clicked]
  const addNewUser = () => {
    setIsAddNewUserOpen(true)
  }

  // close modals org assignment create
  const closeModalAddNewUser = () => {
    setIsAddNewUserOpen(false)
  }

  const handleChangeSearch = (event: any) => {
    setSearchUser(event.target.value)
  }

  // eslint-disable-next-line prettier/prettier
  const assignmentsFilter = assignments.filter(item => item.email?.toLowerCase().includes(searchUser))

  return defaultUserAssignment ? (
    <div className="flex flex-column pa5">
      <div className="flex-row">
        <div className="fl pr2">
          <h3>
            {intl.formatMessage({
              id: 'store/my-organization.my-organization.users-in-organization',
            })}
          </h3>
        </div>
        <div className="fl pl3 mt5">
          <Button
            variation="secondary"
            size="small"
            onClick={() => addNewUser()}>
            {intl.formatMessage({
              id: 'store/my-organization.my-user.table.button.add-new',
            })}
          </Button>
        </div>
      </div>
      <div className="flex flex-column">
        <div>
          <Input
            placeholder="Search"
            value={searchUser}
            onChange={handleChangeSearch}
          />
        </div>
        <div>
          <div className="mb5">
            {assignmentsFilter.map(
              (assignment: OrganizationAssignment, index: number) => {
                return (
                  <div key={`list-item-${index}`}>
                    <UserListItem
                      isCurrentUserAdmin={isCurrentUserAdmin}
                      isDefaultAssignment={
                        defaultUserAssignment.id == assignment.id
                      }
                      orgAssignment={assignment}
                      edit={editUser}
                      deleteAssignment={deleteUserAssignment}
                    />
                  </div>
                )
              }
            )}
          </div>
        </div>
        <UserConfirmationModal
          isOpen={isDeleteConfirmationOpen}
          isLoading={deleteConfirmationLoading}
          onConfirm={confirmDelete}
          onClose={closeDelete}
          assignment={sharedOrgAssignment}
          confirmAction={intl.formatMessage({
            id: 'store/my-organization.my-user.delete-confirmation-action',
          })}
          message={intl.formatMessage({
            id: 'store/my-organization.my-user.delete-confirmation-message',
          })}
        />
        <UserEditModal
          isOpen={isUserEditOpen}
          onClose={closeUserEditModal}
          onSave={closeUserEditModal}
          orgAssignment={sharedOrgAssignment}
          roles={roles}
          showToast={showToast}
          isCurrentUserAdmin={isCurrentUserAdmin}
        />
        <AddUser
          roles={roles}
          organizationId={organizationId}
          isOpen={isAddNewUserOpen}
          onClose={closeModalAddNewUser}
          onSuccess={closeModalAddNewUser}
          showToast={showToast}
          isCurrentUserAdmin={isCurrentUserAdmin}
          existingUsers={assignments.map((assignment: OrganizationAssignment) =>
            pathOr('', ['personaId_linked', 'email'], assignment)
          )}
        />
      </div>
    </div>
  ) : (
    <div />
  )
}

export default injectIntl(MyUsers)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/DefaultAssignmentInfo.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { useState } from 'react'
import { injectIntl } from 'react-intl'
import { reject, filter, propEq, pathOr } from 'ramda'
import { Button } from 'vtex.styleguide'
import { useApolloClient, useMutation } from 'react-apollo'

import WarningModal from './modals/WarningModal'
import ConfirmationModal from './modals/ConfirmationModal'

import DOCUMENTS from '../graphql/documents.graphql'
import UPDATE_DOCUMENT from '../graphql/updateDocument.graphql'
import DELETE_DOCUMENT from '../graphql/deleteDocument.graphql'

import { getErrorMessage } from '../utils/graphqlErrorHandler'
import { documentSerializer } from '../utils/documentSerializer'
import {
  ORG_ASSIGNMENT,
  ORG_ASSIGNMENT_FIELDS,
  ORG_ASSIGNMENT_SCHEMA,
  CLIENT_ACRONYM,
  CLIENT_FIELDS,
  BUSINESS_ORGANIZATION,
} from '../utils/const'

import { updateCacheProfile } from '../utils/cacheUtils'

interface Props {
  clientId: string
  defaultAssignment: OrganizationAssignment
  userRole: any
  infoUpdated: () => void
  showToast: (message: any) => void
  intl: any
  isOrgAdmin: boolean
}

const DefaultAssignmentInfo = ({
  clientId,
  defaultAssignment,
  userRole,
  infoUpdated,
  showToast,
  intl,
  isOrgAdmin,
}: Props) => {
  const [isLeaveWarningOpen, setIsLeaveWarningOpen] = useState(false)
  const [
    isDeleteAssignmentWarningOpen,
    setIsDeleteAssignmentWarningOpen,
  ] = useState(false)

  const [
    isDeleteOrgConfirmationOpen,
    setIsDeleteOrgConfirmationOpen,
  ] = useState(false)

  const [
    deleteOrgConfirmationLoading,
    setDeleteOrgConfirmationLoading,
  ] = useState(false)

  const [isLeaveOrgConfirmationOpen, setIsLeaveOrgConfirmationOpen] = useState(
    false
  )

  const [
    leaveOrgConfirmationLoading,
    setLeaveOrgConfirmationLoading,
  ] = useState(false)

  const [isLeaveBtnLoading, setIsLeaveBtnLoading] = useState(false)
  const [isDeleteBtnLoading, setIsDeleteBtnLoading] = useState(false)

  const client = useApolloClient()
  const [updateDocument] = useMutation(UPDATE_DOCUMENT)
  const [deleteDocument] = useMutation(DELETE_DOCUMENT)

  // Cancel leave
  const closeLeaveOrganization = () => {
    setIsLeaveOrgConfirmationOpen(false)
  }

  // Cancel leave warning
  const closeLeaveOrganizationMessageModal = () => {
    setIsLeaveWarningOpen(false)
  }

  // Check conditions before leave - [Leave btn clicked]
  const leaveOrganization = () => {
    const orgId = pathOr('', ['businessOrganizationId'], defaultAssignment)
    const email = pathOr('', ['email'], defaultAssignment)
    setIsLeaveBtnLoading(true)

    // get all approved organization assignments
    client
      .query({
        query: DOCUMENTS,
        variables: {
          acronym: CLIENT_ACRONYM,
          fields: CLIENT_FIELDS,
          where: `(organizationId=${orgId})`,
        },
        fetchPolicy: 'no-cache',
      })
      .then(({ data }: any) => {
        if (data) {
          const clients = documentSerializer(data ? data.myDocuments : [])

          // orgAdmins belongs to this organization
          const orgAdmins = filter(propEq('isOrgAdmin', 'true'), clients)

          // orgAdmins except current user
          const orgAdminsExcept = reject(propEq('email', email), orgAdmins)

          // Ok to leave if
          // ** organization admins except current user
          if (orgAdminsExcept.length > 0) {
            // show leave confirmation
            setIsLeaveOrgConfirmationOpen(true)
            setIsLeaveBtnLoading(false)
          } else {
            // show warning
            setIsLeaveWarningOpen(true)
            setIsLeaveBtnLoading(false)
          }
        }
      })
      .catch((e: any) => {
        setIsLeaveBtnLoading(false)
        const message = getErrorMessage(e)
        showToast({
          message: `${intl.formatMessage({
            id: 'store/my-organization.toast.organization.leave.error',
          })}"${message}"`,
          duration: 5000,
          horizontalPosition: 'right',
        })
        return Promise.resolve({ myDocuments: [] })
      })
  }

  // Confirm leave - [Leave organization]
  const confirmLeaveOrganization = () => {
    setLeaveOrgConfirmationLoading(true)
    const assignmentId = pathOr('', ['id'], defaultAssignment)

    // update organization assignment status to declined
    deleteDocument({
      variables: {
        acronym: ORG_ASSIGNMENT,
        documentId: assignmentId,
      },
    })
      .then(() => {
        // remove client organizationId
        return updateDocument({
          variables: {
            acronym: CLIENT_ACRONYM,
            document: {
              fields: [
                { key: 'id', value: clientId },
                { key: 'organizationId', value: '' },
                { key: 'approved', value: isOrgAdmin ? 'true' : 'false' },
                // { key: 'isOrgAdmin', value: 'false' },
              ],
            },
          },
          update: (cache: any) => updateCacheProfile(cache, ''),
        })
      })
      .then(() => {
        setLeaveOrgConfirmationLoading(false)
        setIsLeaveOrgConfirmationOpen(false)

        infoUpdated()
      })
      .catch((e: any) => {
        const message = getErrorMessage(e)
        setLeaveOrgConfirmationLoading(false)
        setIsLeaveOrgConfirmationOpen(false)
        showToast({
          message: `${intl.formatMessage({
            id: 'store/my-organization.toast.organization.leave.error',
          })}"${message}"`,
          duration: 5000,
          horizontalPosition: 'right',
        })
      })
  }

  // close delete warning
  const closeDeleteAssignmentWarningModal = () => {
    setIsDeleteAssignmentWarningOpen(false)
  }

  // delete confirmation open
  const deleteOrganization = () => {
    setIsDeleteOrgConfirmationOpen(true)
  }

  // close delete confirmation
  const closeDeleteOrganization = () => {
    setIsDeleteOrgConfirmationOpen(false)
  }

  // Check conditions before delete - [Delete btn clicked]
  const deleteCurrentOrganization = () => {
    const orgId = pathOr('', ['businessOrganizationId'], defaultAssignment)
    const email = pathOr('', ['email'], defaultAssignment)
    setIsDeleteBtnLoading(true)

    // get all approved organization assignments
    client
      .query({
        query: DOCUMENTS,
        variables: {
          acronym: ORG_ASSIGNMENT,
          schema: ORG_ASSIGNMENT_SCHEMA,
          fields: ORG_ASSIGNMENT_FIELDS,
          where: `(businessOrganizationId=${orgId})`,
        },
        fetchPolicy: 'no-cache',
      })
      .then(({ data }: any) => {
        if (data) {
          const assignmentsData = documentSerializer(
            data ? data.myDocuments : []
          )

          // assignments except current user
          const assignmentsExceptMe = reject(
            propEq('email', email),
            assignmentsData
          )

          // Delete organization if
          // ** No other user exists
          if (assignmentsExceptMe && assignmentsExceptMe.length > 0) {
            setIsDeleteAssignmentWarningOpen(true)
            setIsDeleteBtnLoading(false)
          } else {
            setIsDeleteBtnLoading(false)
            deleteOrganization()
          }
        }
      })
      .catch((e: any) => {
        setIsDeleteBtnLoading(false)
        const message = getErrorMessage(e)
        showToast({
          message: `${intl.formatMessage({
            id: 'store/my-organization.toast.organization.leave.error',
          })}"${message}"`,
          duration: 5000,
          horizontalPosition: 'right',
        })
        return Promise.resolve({ myDocuments: [] })
      })
  }

  // Confirm delete - [Delete organization]
  const confirmDeleteOrganization = () => {
    setDeleteOrgConfirmationLoading(true)
    const assignmentId = pathOr('', ['id'], defaultAssignment)

    // delete current organization assignment
    return deleteDocument({
      variables: {
        acronym: ORG_ASSIGNMENT,
        documentId: assignmentId,
      },
    })
      .then(() => {
        const orgId: string = pathOr(
          '',
          ['businessOrganizationId'],
          defaultAssignment
        )

        // delete organization
        return deleteDocument({
          variables: {
            acronym: BUSINESS_ORGANIZATION,
            documentId: orgId,
          },
        })
      })
      .then(() => {
        // remove client organization id
        return updateDocument({
          variables: {
            acronym: CLIENT_ACRONYM,
            document: {
              fields: [
                { key: 'id', value: clientId },
                { key: 'organizationId', value: '' },
                { key: 'approved', value: isOrgAdmin ? 'true' : 'false' },
                // { key: 'isOrgAdmin', value: 'false' },
              ],
            },
          },
          update: (cache: any) => updateCacheProfile(cache, ''),
        })
      })
      .then(() => {
        setDeleteOrgConfirmationLoading(false)
        setIsDeleteOrgConfirmationOpen(false)
        infoUpdated()
      })
      .catch((e: any) => {
        const message = getErrorMessage(e)
        setDeleteOrgConfirmationLoading(false)
        setIsDeleteOrgConfirmationOpen(false)
        showToast({
          message: `${intl.formatMessage({
            id: 'store/my-organization.toast.organization.delete.error',
          })} "${message}"`,
          duration: 5000,
          horizontalPosition: 'right',
        })
      })
  }

  return (
    <div className="pa5">
      <div>
        <h3>
          {intl.formatMessage({
            id: 'store/my-organization.my-organization.organization',
          })}
        </h3>
      </div>
      <div className="flex flex-row">
        <div className="fl mt3 w-40">
          <div className="w-100 pt2 pb2">
            <span>
              {intl.formatMessage({
                id: 'store/my-organization.my-organization.organization.name',
              })}
              :{' '}
            </span>
            <span className="b">
              {pathOr(
                '',
                ['businessOrganizationId_linked', 'name'],
                defaultAssignment
              )}
            </span>
          </div>
          <div className="w-100 pt2 pb2">
            <span>
              {intl.formatMessage({
                id: 'store/my-organization.my-organization.role',
              })}{' '}
            </span>
            :{' '}
            <span className="b">
              {' '}
              {userRole && userRole.label ? userRole.label : ''}
            </span>
          </div>
          <div className="w-100 pt2 pb2"></div>
        </div>
        <div className="fl w-20 flex flex-column">
          <span className="pa2">
            <Button
              variation="danger-tertiary"
              size="small"
              isLoading={isLeaveBtnLoading}
              onClick={() => leaveOrganization()}
              block>
              {intl.formatMessage({
                id: 'store/my-organization.my-organization.leave',
              })}
            </Button>
          </span>
          {isOrgAdmin && (
            <span className="pa2">
              <Button
                variation="danger-tertiary"
                isLoading={isDeleteBtnLoading}
                size="small"
                onClick={() => deleteCurrentOrganization()}
                block>
                {intl.formatMessage({
                  id: 'store/my-organization.my-organization.delete',
                })}
              </Button>
            </span>
          )}
        </div>
        <WarningModal
          onOk={closeLeaveOrganizationMessageModal}
          onClose={closeLeaveOrganizationMessageModal}
          isOpen={isLeaveWarningOpen}
          assignment={defaultAssignment}
          title={intl.formatMessage({
            id: 'store/my-organization.my-organization.unable-to-leave-title',
          })}
          messageLine1={intl.formatMessage({
            id:
              'store/my-organization.my-organization.unable-to-leave-message1',
          })}
          messageLine2={
            isOrgAdmin
              ? intl.formatMessage({
                  id:
                    'store/my-organization.my-organization.unable-to-leave-manager-message2',
                })
              : intl.formatMessage({
                  id:
                    'store/my-organization.my-organization.unable-to-leave-message2',
                })
          }
        />

        <WarningModal
          onOk={closeDeleteAssignmentWarningModal}
          onClose={closeDeleteAssignmentWarningModal}
          isOpen={isDeleteAssignmentWarningOpen}
          assignment={defaultAssignment}
          title={intl.formatMessage({
            id: 'store/my-organization.my-organization.unable-to-delete-title',
          })}
          messageLine1={intl.formatMessage({
            id:
              'store/my-organization.my-organization.unable-to-delete-message1',
          })}
          messageLine2={intl.formatMessage({
            id:
              'store/my-organization.my-organization.unable-to-delete-message2',
          })}
        />

        <ConfirmationModal
          isOpen={isLeaveOrgConfirmationOpen}
          isLoading={leaveOrgConfirmationLoading}
          onConfirm={confirmLeaveOrganization}
          onClose={closeLeaveOrganization}
          assignment={defaultAssignment}
          confirmAction={intl.formatMessage({
            id: 'store/my-organization.my-organization.button.leave',
          })}
          message={intl.formatMessage({
            id: 'store/my-organization.my-organization.leave.message',
          })}
        />

        <ConfirmationModal
          isOpen={isDeleteOrgConfirmationOpen}
          isLoading={deleteOrgConfirmationLoading}
          onConfirm={confirmDeleteOrganization}
          onClose={closeDeleteOrganization}
          assignment={defaultAssignment}
          confirmAction={intl.formatMessage({
            id: 'store/my-organization.my-organization.button.delete',
          })}
          message={intl.formatMessage({
            id: 'store/my-organization.my-organization.delete.message',
          })}
        />
      </div>
    </div>
  )
}

export default injectIntl(DefaultAssignmentInfo)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/CurrencyInput.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React, { FC, useCallback, useMemo } from 'react'
import { Input } from 'vtex.styleguide'

interface Props extends React.ComponentPropsWithoutRef<typeof Input> {
  separator?: string;
  valueAsString?: boolean;
}

const getDigitsFromValue = (value = '') => value.replace(/(-(?!\d))|[^0-9|-]/g, '') || ''

const padDigits = (digits: string) => {
  const desiredLength = 3
  const actualLength = digits.length

  if (actualLength >= desiredLength) {
    return digits

  }

  const amountToAdd = desiredLength - actualLength
  const padding = '0'.repeat(amountToAdd)

  return padding + digits
}

const removeLeadingZeros = (number: string) =>
  number.replace(/^0+([0-9]+)/, '$1')

const addDecimalToNumber = (number: string, separator: string) => {
  const centsStartingPosition = number.length - 2
  const dollars = removeLeadingZeros(number.substring(0, centsStartingPosition))
  const cents = number.substring(centsStartingPosition)

  return dollars + separator + cents
}

const toCurrency = (separator: string, value?: string) => {
  const digits = getDigitsFromValue(value)
  const digitsWithPadding = padDigits(digits)

  return addDecimalToNumber(digitsWithPadding, separator)
}

const CurrencyInput: FC<Props> = ({
  onChange,
  separator = ',',
  value,
  valueAsString,
  ...props
}) => {
  const handleChange = useCallback(
    (event) => {
      const { value: stringValue } = event.target
      const cents = typeof stringValue === 'string' ? parseInt(stringValue.replace(',', ''), 10) : undefined
      event.persist()

      // eslint-disable-next-line prettier/prettier
      onChange?.(({
        target: {
          value: valueAsString ? toCurrency(separator, stringValue) : cents,
        },
      } as unknown) as React.ChangeEvent<HTMLInputElement>)
    },
    [onChange, valueAsString, separator]
  )

  const innerValue = useMemo(() => {
    const stringValue = typeof value === 'number' ? value.toString() : value

    if (stringValue) {
      return toCurrency(separator, stringValue as string)
    }
    return
  }, [value, separator])

  return (
    <Input
      inputMode="numeric"
      pattern="[0-9,]*"
      {...props}
      value={innerValue}
      onChange={handleChange}
    />
  )
}

export default CurrencyInput

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/__tests__/index.test.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
describe('Product description scenario', () => {
  it('should work', () => {
    expect(1).toBe(1)
  })
})

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/graphql/getProfile.graphql from the organizations VTEX app.

[Assistant]
Here's the implementation:

```graphql
query Profile($customFields: String) {
  profile (customFields: $customFields){
    id
    email
    customFields {
      key
      value
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/graphql/deleteDocument.graphql from the organizations VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation deleteDocument($acronym: String!, $documentId: String!) {
  deleteMyDocument(acronym: $acronym, documentId: $documentId) {
    id
    cacheId
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/graphql/documents.graphql from the organizations VTEX app.

[Assistant]
Here's the implementation:

```graphql
query getDocuments(
  $acronym: String
  $fields: [String]
  $schema: String
  $where: String
  $page: Int
  $pageSize: Int,
  $sort: String
) {
  myDocuments(
    acronym: $acronym
    fields: $fields
    schema: $schema
    where: $where
    page: $page
    pageSize: $pageSize,
    sort: $sort
  ) {
    id
    fields {
      key
      value
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/graphql/createDocument.graphql from the organizations VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation createDocument(
  $acronym: String!
  $document: DocumentInput
  $schema: String
) {
  createMyDocument(acronym: $acronym, document: $document, schema: $schema) {
    id
    cacheId
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/graphql/updateDocument.graphql from the organizations VTEX app.

[Assistant]
Here's the implementation:

```graphql
mutation updateDocument(
  $acronym: String!
  $document: DocumentInput
  $schema: String
) {
  updateMyDocument(acronym: $acronym, document: $document, schema: $schema) {
    id
    cacheId
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/graphql/getSession.graphql from the organizations VTEX app.

[Assistant]
Here's the implementation:

```graphql
query Session {
  getSession {
    id
    adminUserId
    profile {
      id
    }
  }
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/modules/session.ts from the organizations VTEX app.

[Assistant]
Here's the implementation:

```typescript
import { SessionPromise } from 'vtex.render-runtime'

export function getSession() {
  return window &&
    (window as any).__RENDER_8_SESSION__ &&
    (window as any).__RENDER_8_SESSION__.sessionPromise
    ? ((window as any).__RENDER_8_SESSION__.sessionPromise as Promise<
        SessionPromise
      >)
    : null
}

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/modals/UserConfirmationModal.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ModalDialog } from 'vtex.styleguide'
import { pathOr } from 'ramda'
import { injectIntl } from 'react-intl'

interface Props {
  isOpen: boolean
  isLoading: boolean
  onConfirm: Function
  onClose: Function
  assignment: OrganizationAssignment
  confirmAction: string
  message: string
  intl: any
}

const UserConfirmationModal = ({
  isOpen,
  isLoading,
  onConfirm,
  onClose,
  assignment,
  confirmAction,
  message,
  intl,
}: Props) => {
  return (
    <ModalDialog
      centered
      loading={isLoading}
      confirmation={{
        onClick: () => onConfirm(assignment),
        label: confirmAction,
        isDangerous: true,
      }}
      cancelation={{
        onClick: () => onClose(),
        label: intl.formatMessage({
          id: 'store/my-organization.button.cancel',
        }),
      }}
      isOpen={isOpen}
      onClose={() => onClose()}>
      <h1>{confirmAction}</h1>
      <div className="flex flex-column mb5 mt5">
        <div>
          <span>{message}</span>
          <span className="b">{pathOr('', ['email'], assignment)}</span>
        </div>
      </div>
    </ModalDialog>
  )
}

export default injectIntl(UserConfirmationModal)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/modals/WarningModal.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { Modal, Button } from 'vtex.styleguide'
import { pathOr } from 'ramda'
import { injectIntl } from 'react-intl'

interface Props {
  isOpen: boolean
  onOk: Function
  onClose: Function
  assignment: OrganizationAssignment
  title: string
  messageLine1?: string
  messageLine2?: string
  intl: any
}

const WarningModal = ({
  isOpen,
  onOk,
  onClose,
  assignment,
  title,
  messageLine1,
  messageLine2,
  intl,
}: Props) => {
  return (
    <Modal
      isOpen={isOpen}
      title={title}
      responsiveFullScreen
      centered
      bottomBar={
        <div className="nowrap">
          <span className="mr4">
            <Button variation="tertiary" onClick={() => onOk()}>
              {intl.formatMessage({ id: 'store/my-organization.button.ok' })}
            </Button>
          </span>
        </div>
      }
      onClose={() => onClose()}>
      <div className="flex flex-column mb5 mt5">
        <div>
          <span>{messageLine1}</span>
          <span className="b">
            {pathOr('', ['businessOrganizationId_linked', 'name'], assignment)}
          </span>
        </div>
        <div className="mt2">
          <span className="red">{messageLine2}</span>
        </div>
      </div>
    </Modal>
  )
}

export default injectIntl(WarningModal)

```


[System] You are an expert VTEX IO developer. You specialize in building VTEX Store Framework apps, React components, GraphQL APIs, and Node.js services for e-commerce platforms.

[User] Show me the implementation of organizations/react/components/modals/ConfirmationModal.tsx from the organizations VTEX app.

[Assistant]
Here's the implementation:

```tsx
import React from 'react'
import { ModalDialog } from 'vtex.styleguide'
import { pathOr } from 'ramda'
import { injectIntl } from 'react-intl'

interface Props {
  isOpen: boolean
  isLoading: boolean
  onConfirm: Function
  onClose: Function
  assignment: OrganizationAssignment
  confirmAction: string
  message: string
  intl: any
}

const ConfirmationModal = ({
  isOpen,
  isLoading,
  onConfirm,
  onClose,
  assignment,
  confirmAction,
  message,
  intl,
}: Props) => {
  return (
    <ModalDialog
      centered
      loading={isLoading}
      confirmation={{
        onClick: () => onConfirm(assignment),
        label: confirmAction,
        isDangerous: true,
      }}
      cancelation={{
        onClick: () => onClose(),
        label: 'Cancel',
      }}
      isOpen={isOpen}
      onClose={() => onClose()}>
      <h1>
        {confirmAction}{' '}
        {intl.formatMessage({
          id: 'store/my-organization.errors.organization.text',
        })}
      </h1>
      <div className="flex flex-column mb5 mt5">
        <div>
          <span>{message}</span>
          <span className="b">
            {pathOr('', ['businessOrganizationId_linked', 'name'], assignment)}
          </span>
        </div>
      </div>
    </ModalDialog>
  )
}

export default injectIntl(ConfirmationModal)

```