@os-team/profile 1.2.6 → 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/components/profile/ProfileDeleteAccountModal.d.ts +8 -0
  2. package/dist/components/profile/ProfileDeleteAccountModal.d.ts.map +1 -0
  3. package/dist/components/profile/ProfileDeleteAccountModal.js +119 -0
  4. package/dist/components/profile/ProfileDrawerContent.d.ts.map +1 -1
  5. package/dist/components/profile/ProfileDrawerContent.js +17 -1
  6. package/dist/components/profile/UserAvatarAddon.d.ts.map +1 -1
  7. package/dist/components/profile/UserAvatarAddon.js +1 -2
  8. package/dist/components/profile/__generated__/ProfileDeleteAccountModalConfirmMutation.graphql.d.ts +24 -0
  9. package/dist/components/profile/__generated__/ProfileDeleteAccountModalConfirmMutation.graphql.d.ts.map +1 -0
  10. package/dist/components/profile/__generated__/ProfileDeleteAccountModalConfirmMutation.graphql.js +65 -0
  11. package/dist/components/profile/__generated__/ProfileDeleteAccountModalRequestMutation.graphql.d.ts +19 -0
  12. package/dist/components/profile/__generated__/ProfileDeleteAccountModalRequestMutation.graphql.d.ts.map +1 -0
  13. package/dist/components/profile/__generated__/ProfileDeleteAccountModalRequestMutation.graphql.js +56 -0
  14. package/dist/components/session/SessionList.d.ts.map +1 -1
  15. package/dist/components/session/SessionListItem.d.ts.map +1 -1
  16. package/dist/components/session/formatDate.d.ts.map +1 -1
  17. package/dist/components/session/getLastSeen.d.ts.map +1 -1
  18. package/dist/utils/getError.d.ts +2 -0
  19. package/dist/utils/getError.d.ts.map +1 -1
  20. package/dist/utils/getError.js +14 -1
  21. package/dist/utils/getUserFullName.d.ts.map +1 -1
  22. package/dist/utils/handleFormErrors.d.ts.map +1 -1
  23. package/package.json +24 -24
  24. package/src/lib/components/profile/ProfileDeleteAccountModal.tsx +170 -0
  25. package/src/lib/components/profile/ProfileDrawerContent.tsx +20 -0
  26. package/src/lib/components/profile/UserAvatarAddon.tsx +1 -2
  27. package/src/lib/components/profile/__generated__/ProfileDeleteAccountModalConfirmMutation.graphql.ts +92 -0
  28. package/src/lib/components/profile/__generated__/ProfileDeleteAccountModalRequestMutation.graphql.ts +74 -0
  29. package/src/lib/utils/getError.ts +15 -0
  30. package/src/schema.graphql +11 -1
  31. package/src/utils/getError.ts +15 -0
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface ProfileDeleteAccountModalProps {
3
+ visible: boolean;
4
+ onClose: () => void;
5
+ }
6
+ declare const ProfileDeleteAccountModal: React.FC<ProfileDeleteAccountModalProps>;
7
+ export default ProfileDeleteAccountModal;
8
+ //# sourceMappingURL=ProfileDeleteAccountModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileDeleteAccountModal.d.ts","sourceRoot":"","sources":["../../../src/lib/components/profile/ProfileDeleteAccountModal.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAoD,MAAM,OAAO,CAAC;AAoDzE,UAAU,8BAA8B;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,yBAAyB,EAAE,KAAK,CAAC,EAAE,CAAC,8BAA8B,CAmGvE,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
@@ -0,0 +1,119 @@
1
+ var _ProfileDeleteAccountModalRequestMutation, _ProfileDeleteAccountModalConfirmMutation;
2
+ import { Alert, Form, FormItem, Input, message, Modal } from '@os-design/core';
3
+ import { FormProvider, useExistingForm, useForm } from '@os-design/form';
4
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { useMutation } from 'react-relay';
7
+ import handleFormErrors from '../../utils/handleFormErrors';
8
+ import FormError from '../shared/FormError';
9
+ import getError from '../../utils/getError';
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const Step1Form = () => {
12
+ const {
13
+ t
14
+ } = useTranslation(['profile']);
15
+ return /*#__PURE__*/_jsx(Alert, {
16
+ type: "info",
17
+ children: t('profile:deleteAccountModal.requestAlert')
18
+ });
19
+ };
20
+ const Step2Form = () => {
21
+ const {
22
+ Field
23
+ } = useExistingForm();
24
+ const {
25
+ t
26
+ } = useTranslation(['profile']);
27
+ const codeData = useMemo(() => ({
28
+ label: t('profile:deleteAccountModal.code.label'),
29
+ placeholder: t('profile:deleteAccountModal.code.placeholder')
30
+ }), [t]);
31
+ return /*#__PURE__*/_jsxs(Form, {
32
+ children: [/*#__PURE__*/_jsx(Alert, {
33
+ type: "info",
34
+ children: t('profile:deleteAccountModal.confirmAlert')
35
+ }), /*#__PURE__*/_jsx(Field, {
36
+ name: "code",
37
+ data: codeData,
38
+ render: (props, {
39
+ error
40
+ }, data) => /*#__PURE__*/_jsx(FormItem, {
41
+ label: data.label,
42
+ error: error,
43
+ children: /*#__PURE__*/_jsx(Input, {
44
+ type: "number",
45
+ placeholder: data.placeholder,
46
+ ...props
47
+ })
48
+ })
49
+ }), /*#__PURE__*/_jsx(FormError, {})]
50
+ });
51
+ };
52
+ const ProfileDeleteAccountModal = ({
53
+ visible,
54
+ onClose
55
+ }) => {
56
+ const {
57
+ t
58
+ } = useTranslation(['profile']);
59
+ const [step, setStep] = useState(1);
60
+ const initValues = useMemo(() => ({
61
+ code: ''
62
+ }), []);
63
+ const {
64
+ form
65
+ } = useForm(initValues);
66
+
67
+ // Reset the form when the modal is opened
68
+ useEffect(() => {
69
+ if (visible) {
70
+ form.reset();
71
+ setStep(1);
72
+ }
73
+ }, [form, visible]);
74
+ const [requestCommit, requestLoading] = useMutation(_ProfileDeleteAccountModalRequestMutation !== void 0 ? _ProfileDeleteAccountModalRequestMutation : (_ProfileDeleteAccountModalRequestMutation = require("./__generated__/ProfileDeleteAccountModalRequestMutation.graphql"), _ProfileDeleteAccountModalRequestMutation.hash && _ProfileDeleteAccountModalRequestMutation.hash !== "cf5b3f55e2cd09b456ad657b90b72657" && console.error("The definition of 'ProfileDeleteAccountModalRequestMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _ProfileDeleteAccountModalRequestMutation));
75
+ const [confirmCommit, confirmLoading] = useMutation(_ProfileDeleteAccountModalConfirmMutation !== void 0 ? _ProfileDeleteAccountModalConfirmMutation : (_ProfileDeleteAccountModalConfirmMutation = require("./__generated__/ProfileDeleteAccountModalConfirmMutation.graphql"), _ProfileDeleteAccountModalConfirmMutation.hash && _ProfileDeleteAccountModalConfirmMutation.hash !== "99038f6b8c389648b94a77aa065ff902" && console.error("The definition of 'ProfileDeleteAccountModalConfirmMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _ProfileDeleteAccountModalConfirmMutation));
76
+ const onSubmitRequest = useCallback(() => {
77
+ requestCommit({
78
+ variables: {},
79
+ onError: error => message.error(getError(error).message),
80
+ onCompleted: () => setStep(2)
81
+ });
82
+ }, [requestCommit]);
83
+ const onSubmitConfirm = useCallback(() => {
84
+ confirmCommit({
85
+ variables: {
86
+ input: {
87
+ code: form.values.get('code')
88
+ }
89
+ },
90
+ onError: error => handleFormErrors(form, error),
91
+ onCompleted: () => {
92
+ onClose();
93
+ window.location.href = '/auth/';
94
+ }
95
+ });
96
+ }, [confirmCommit, form, onClose]);
97
+ const modalProps = useMemo(() => step === 1 ? {
98
+ okText: t('profile:deleteAccountModal.requestButton'),
99
+ okLoading: requestLoading,
100
+ onOk: onSubmitRequest
101
+ } : {
102
+ okText: t('profile:deleteAccountModal.confirmButton'),
103
+ okLoading: confirmLoading,
104
+ onOk: onSubmitConfirm,
105
+ okDanger: true
106
+ }, [confirmLoading, onSubmitConfirm, onSubmitRequest, requestLoading, step, t]);
107
+ const children = useMemo(() => step === 1 ? /*#__PURE__*/_jsx(Step1Form, {}) : /*#__PURE__*/_jsx(Step2Form, {}), [step]);
108
+ return /*#__PURE__*/_jsx(Modal, {
109
+ title: t('profile:deleteAccountModal.title'),
110
+ visible: visible,
111
+ onClose: onClose,
112
+ ...modalProps,
113
+ children: /*#__PURE__*/_jsx(FormProvider, {
114
+ form: form,
115
+ children: children
116
+ })
117
+ });
118
+ };
119
+ export default ProfileDeleteAccountModal;
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileDrawerContent.d.ts","sourceRoot":"","sources":["../../../src/lib/components/profile/ProfileDrawerContent.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAYtE,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AA+MD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAwC7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"ProfileDrawerContent.d.ts","sourceRoot":"","sources":["../../../src/lib/components/profile/ProfileDrawerContent.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAatE,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAiOD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAyC7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -11,6 +11,7 @@ import { useProfile } from './ProfileContext';
11
11
  import ProfileUpdateNameModal from './ProfileUpdateNameModal';
12
12
  import ProfileUpdatePasswordModal from './ProfileUpdatePasswordModal';
13
13
  import UserAvatar from './UserAvatar';
14
+ import ProfileDeleteAccountModal from './ProfileDeleteAccountModal';
14
15
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
15
16
  const AvatarContainer = styled.div`
16
17
  display: flex;
@@ -147,6 +148,21 @@ const ChangePasswordButton = () => {
147
148
  })]
148
149
  });
149
150
  };
151
+ const DeleteAccountButton = () => {
152
+ const {
153
+ t
154
+ } = useTranslation(['profile']);
155
+ const [modalVisible, setModalVisible] = useState(false);
156
+ return /*#__PURE__*/_jsxs(_Fragment, {
157
+ children: [/*#__PURE__*/_jsx(ProfileButton, {
158
+ onClick: () => setModalVisible(true),
159
+ children: t('profile:deleteAccount')
160
+ }), /*#__PURE__*/_jsx(ProfileDeleteAccountModal, {
161
+ visible: modalVisible,
162
+ onClose: () => setModalVisible(false)
163
+ })]
164
+ });
165
+ };
150
166
  const SignOutButton = () => {
151
167
  const {
152
168
  t
@@ -195,7 +211,7 @@ const ProfileDrawerContent = ({
195
211
  hasAvatar: !!avatar
196
212
  }), /*#__PURE__*/_jsx(UpdateNameButton, {
197
213
  hasName: !!fullName
198
- }), /*#__PURE__*/_jsx(ChangePasswordButton, {}), actions, /*#__PURE__*/_jsx(SignOutButton, {}), children]
214
+ }), /*#__PURE__*/_jsx(ChangePasswordButton, {}), actions, /*#__PURE__*/_jsx(DeleteAccountButton, {}), /*#__PURE__*/_jsx(SignOutButton, {}), children]
199
215
  }), /*#__PURE__*/_jsx(Footer, {
200
216
  children: /*#__PURE__*/_jsx(ThemeSwitcher, {})
201
217
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"UserAvatarAddon.d.ts","sourceRoot":"","sources":["../../../src/lib/components/profile/UserAvatarAddon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AA0BD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwBnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"UserAvatarAddon.d.ts","sourceRoot":"","sources":["../../../src/lib/components/profile/UserAvatarAddon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AA0BD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuBnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -19,7 +19,7 @@ const StyledUserAvatar = styled(UserAvatar)`
19
19
 
20
20
  @media (hover: hover) {
21
21
  &:hover,
22
- &:focus {
22
+ &:focus-visible {
23
23
  opacity: 0.7;
24
24
  }
25
25
  ${transitionStyles('opacity')};
@@ -42,7 +42,6 @@ const UserAvatarAddon = ({
42
42
  onKeyDown: e => {
43
43
  if (e.key === 'Enter') onClick();
44
44
  },
45
- onMouseDown: e => e.preventDefault(),
46
45
  ...rest
47
46
  })
48
47
  })
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @generated SignedSource<<d507b3267ba624a9d0277cf9e6c095dc>>
3
+ * @lightSyntaxTransform
4
+ * @nogrep
5
+ */
6
+ import { ConcreteRequest } from 'relay-runtime';
7
+ export type ConfirmDeleteAccountInput = {
8
+ code: string;
9
+ };
10
+ export type ProfileDeleteAccountModalConfirmMutation$variables = {
11
+ input: ConfirmDeleteAccountInput;
12
+ };
13
+ export type ProfileDeleteAccountModalConfirmMutation$data = {
14
+ readonly confirmDeleteAccount: {
15
+ readonly ok: boolean;
16
+ };
17
+ };
18
+ export type ProfileDeleteAccountModalConfirmMutation = {
19
+ response: ProfileDeleteAccountModalConfirmMutation$data;
20
+ variables: ProfileDeleteAccountModalConfirmMutation$variables;
21
+ };
22
+ declare const node: ConcreteRequest;
23
+ export default node;
24
+ //# sourceMappingURL=ProfileDeleteAccountModalConfirmMutation.graphql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileDeleteAccountModalConfirmMutation.graphql.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/profile/__generated__/ProfileDeleteAccountModalConfirmMutation.graphql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AACF,MAAM,MAAM,kDAAkD,GAAG;IAC/D,KAAK,EAAE,yBAAyB,CAAC;CAClC,CAAC;AACF,MAAM,MAAM,6CAA6C,GAAG;IAC1D,QAAQ,CAAC,oBAAoB,EAAE;QAC7B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;KACtB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,wCAAwC,GAAG;IACrD,QAAQ,EAAE,6CAA6C,CAAC;IACxD,SAAS,EAAE,kDAAkD,CAAC;CAC/D,CAAC;AAEF,QAAA,MAAM,IAAI,EAAE,eA4DR,CAAC;AAIL,eAAe,IAAI,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @generated SignedSource<<d507b3267ba624a9d0277cf9e6c095dc>>
3
+ * @lightSyntaxTransform
4
+ * @nogrep
5
+ */
6
+
7
+ /* tslint:disable */
8
+ /* eslint-disable */
9
+ // @ts-nocheck
10
+
11
+ const node = function () {
12
+ var v0 = [{
13
+ "defaultValue": null,
14
+ "kind": "LocalArgument",
15
+ "name": "input"
16
+ }],
17
+ v1 = [{
18
+ "alias": null,
19
+ "args": [{
20
+ "kind": "Variable",
21
+ "name": "input",
22
+ "variableName": "input"
23
+ }],
24
+ "concreteType": "StatusPayload",
25
+ "kind": "LinkedField",
26
+ "name": "confirmDeleteAccount",
27
+ "plural": false,
28
+ "selections": [{
29
+ "alias": null,
30
+ "args": null,
31
+ "kind": "ScalarField",
32
+ "name": "ok",
33
+ "storageKey": null
34
+ }],
35
+ "storageKey": null
36
+ }];
37
+ return {
38
+ "fragment": {
39
+ "argumentDefinitions": v0 /*: any*/,
40
+ "kind": "Fragment",
41
+ "metadata": null,
42
+ "name": "ProfileDeleteAccountModalConfirmMutation",
43
+ "selections": v1 /*: any*/,
44
+ "type": "Mutation",
45
+ "abstractKey": null
46
+ },
47
+ "kind": "Request",
48
+ "operation": {
49
+ "argumentDefinitions": v0 /*: any*/,
50
+ "kind": "Operation",
51
+ "name": "ProfileDeleteAccountModalConfirmMutation",
52
+ "selections": v1 /*: any*/
53
+ },
54
+ "params": {
55
+ "cacheID": "3b50f27a2aeb5cad62d9dd9aea21c926",
56
+ "id": null,
57
+ "metadata": {},
58
+ "name": "ProfileDeleteAccountModalConfirmMutation",
59
+ "operationKind": "mutation",
60
+ "text": "mutation ProfileDeleteAccountModalConfirmMutation(\n $input: ConfirmDeleteAccountInput!\n) {\n confirmDeleteAccount(input: $input) {\n ok\n }\n}\n"
61
+ }
62
+ };
63
+ }();
64
+ node.hash = "99038f6b8c389648b94a77aa065ff902";
65
+ export default node;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @generated SignedSource<<fcad4b832cf53f5a8f514b3dabdb210b>>
3
+ * @lightSyntaxTransform
4
+ * @nogrep
5
+ */
6
+ import { ConcreteRequest } from 'relay-runtime';
7
+ export type ProfileDeleteAccountModalRequestMutation$variables = Record<PropertyKey, never>;
8
+ export type ProfileDeleteAccountModalRequestMutation$data = {
9
+ readonly requestDeleteAccount: {
10
+ readonly ok: boolean;
11
+ };
12
+ };
13
+ export type ProfileDeleteAccountModalRequestMutation = {
14
+ response: ProfileDeleteAccountModalRequestMutation$data;
15
+ variables: ProfileDeleteAccountModalRequestMutation$variables;
16
+ };
17
+ declare const node: ConcreteRequest;
18
+ export default node;
19
+ //# sourceMappingURL=ProfileDeleteAccountModalRequestMutation.graphql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProfileDeleteAccountModalRequestMutation.graphql.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/profile/__generated__/ProfileDeleteAccountModalRequestMutation.graphql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,MAAM,MAAM,kDAAkD,GAAG,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAC5F,MAAM,MAAM,6CAA6C,GAAG;IAC1D,QAAQ,CAAC,oBAAoB,EAAE;QAC7B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;KACtB,CAAC;CACH,CAAC;AACF,MAAM,MAAM,wCAAwC,GAAG;IACrD,QAAQ,EAAE,6CAA6C,CAAC;IACxD,SAAS,EAAE,kDAAkD,CAAC;CAC/D,CAAC;AAEF,QAAA,MAAM,IAAI,EAAE,eA+CR,CAAC;AAIL,eAAe,IAAI,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @generated SignedSource<<fcad4b832cf53f5a8f514b3dabdb210b>>
3
+ * @lightSyntaxTransform
4
+ * @nogrep
5
+ */
6
+
7
+ /* tslint:disable */
8
+ /* eslint-disable */
9
+ // @ts-nocheck
10
+
11
+ const node = function () {
12
+ var v0 = [{
13
+ "alias": null,
14
+ "args": null,
15
+ "concreteType": "StatusPayload",
16
+ "kind": "LinkedField",
17
+ "name": "requestDeleteAccount",
18
+ "plural": false,
19
+ "selections": [{
20
+ "alias": null,
21
+ "args": null,
22
+ "kind": "ScalarField",
23
+ "name": "ok",
24
+ "storageKey": null
25
+ }],
26
+ "storageKey": null
27
+ }];
28
+ return {
29
+ "fragment": {
30
+ "argumentDefinitions": [],
31
+ "kind": "Fragment",
32
+ "metadata": null,
33
+ "name": "ProfileDeleteAccountModalRequestMutation",
34
+ "selections": v0 /*: any*/,
35
+ "type": "Mutation",
36
+ "abstractKey": null
37
+ },
38
+ "kind": "Request",
39
+ "operation": {
40
+ "argumentDefinitions": [],
41
+ "kind": "Operation",
42
+ "name": "ProfileDeleteAccountModalRequestMutation",
43
+ "selections": v0 /*: any*/
44
+ },
45
+ "params": {
46
+ "cacheID": "cd42c1d7733a3434f5df551f574bc2e4",
47
+ "id": null,
48
+ "metadata": {},
49
+ "name": "ProfileDeleteAccountModalRequestMutation",
50
+ "operationKind": "mutation",
51
+ "text": "mutation ProfileDeleteAccountModalRequestMutation {\n requestDeleteAccount {\n ok\n }\n}\n"
52
+ }
53
+ };
54
+ }();
55
+ node.hash = "cf5b3f55e2cd09b456ad657b90b72657";
56
+ export default node;
@@ -1 +1 @@
1
- {"version":3,"file":"SessionList.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/SessionList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAKpD,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,8CAA8C,CAAC;AAc7F,UAAU,gBAAgB;IACxB,WAAW,EAAE,wBAAwB,CAAC;CACvC;AAED,eAAO,MAAM,KAAK;;SAhBP,MAAO,WAAW;qFAmB5B,CAAC;AAEF,eAAO,MAAM,IAAI;;SArBN,MAAO,WAAW;qFAwB5B,CAAC;AAaF,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAqF3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"SessionList.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/SessionList.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAKpD,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,8CAA8C,CAAC;AAc7F,UAAU,gBAAgB;IACxB,WAAW,EAAE,wBAAwB,CAAC;CACvC;AAED,eAAO,MAAM,KAAK;;SAlB4B,MAAO,WAAW;qFAqB/D,CAAC;AAEF,eAAO,MAAM,IAAI;;SAvB6B,MAAO,WAAW;qFA0B/D,CAAC;AAaF,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAqF3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SessionListItem.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/SessionListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAgBpD,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,iDAAiD,CAAC;AA6BnG,UAAU,oBAAoB;IAC5B,UAAU,EAAE,2BAA2B,CAAC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,SAAS;;SAnClB,MAAO,WAAW;qFA6DrB,CAAC;AAOF,eAAO,MAAM,OAAO;;SApEhB,MAAO,WAAW;qFAuErB,CAAC;AAmDF,eAAO,MAAM,aAAa;;SA1HtB,MAAO,WAAW;qFA+HrB,CAAC;AAEF,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,eAAO,MAAM,IAAI;;SAgEyB,MAAO,WACjD;iGAjDC,CAAC;AAaF,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2InD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"SessionListItem.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/SessionListItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAgBpD,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,iDAAiD,CAAC;AA6BnG,UAAU,oBAAoB;IAC5B,UAAU,EAAE,2BAA2B,CAAC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,SAAS;;SArC4C,MAAO,WACnE;qFA8DL,CAAC;AAOF,eAAO,MAAM,OAAO;;SAtE8C,MAAO,WACnE;qFAwEL,CAAC;AAmDF,eAAO,MAAM,aAAa;;SA5HwC,MAAO,WACnE;qFAgIL,CAAC;AAEF,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,eAAO,MAAM,IAAI;;SAoD4B,MAAO,WACnD;iGArCA,CAAC;AAaF,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2InD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"formatDate.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/formatDate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzD,QAAA,MAAM,UAAU,cACH,MAAM,KACd,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,OAC7B,MAAM,KACV,MAYF,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"formatDate.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/formatDate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzD,QAAA,MAAM,UAAU,GACd,WAAW,MAAM,EACjB,GAAG,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,EAClC,KAAK,MAAM,KACV,MAYF,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"getLastSeen.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/getLastSeen.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,WAAW,eACH,MAAM,KACjB,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC,GAAG,IAe9C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"getLastSeen.d.ts","sourceRoot":"","sources":["../../../src/lib/components/session/getLastSeen.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,WAAW,GACf,YAAY,MAAM,KACjB,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC,GAAG,IAe9C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -5,8 +5,10 @@ interface Constraint {
5
5
  interface ErrorObject {
6
6
  code: string;
7
7
  message: string;
8
+ extensions?: Record<string, unknown>;
8
9
  data?: Record<string, Constraint>;
9
10
  }
10
11
  declare const getError: (error: unknown) => ErrorObject;
12
+ export declare const getErrorMessage: (error: unknown) => string;
11
13
  export default getError;
12
14
  //# sourceMappingURL=getError.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getError.d.ts","sourceRoot":"","sources":["../../src/lib/utils/getError.ts"],"names":[],"mappings":"AAAA,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAmBD,QAAA,MAAM,QAAQ,UAAW,OAAO,KAAG,WAsElC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"getError.d.ts","sourceRoot":"","sources":["../../src/lib/utils/getError.ts"],"names":[],"mappings":"AAAA,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAmBD,QAAA,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,WAwElC,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,MAUhD,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -40,13 +40,26 @@ const getError = error => {
40
40
  if (!('data' in firstError.extensions) || !isData(firstError.extensions.data)) {
41
41
  return {
42
42
  code: firstError.extensions.code,
43
- message: firstError.message
43
+ message: firstError.message,
44
+ extensions: firstError.extensions
44
45
  };
45
46
  }
46
47
  return {
47
48
  code: firstError.extensions.code,
48
49
  message: firstError.message,
50
+ extensions: firstError.extensions,
49
51
  data: firstError.extensions.data
50
52
  };
51
53
  };
54
+ export const getErrorMessage = error => {
55
+ const err = getError(error);
56
+ let msg = err.message;
57
+ if (err.data) {
58
+ const constraints = Object.values(err.data);
59
+ if (constraints.length > 0) {
60
+ msg = constraints[0].message;
61
+ }
62
+ }
63
+ return msg;
64
+ };
52
65
  export default getError;
@@ -1 +1 @@
1
- {"version":3,"file":"getUserFullName.d.ts","sourceRoot":"","sources":["../../src/lib/utils/getUserFullName.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,QAAA,MAAM,eAAe,mCAAoC,IAAI,KAAG,MAK/D,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"getUserFullName.d.ts","sourceRoot":"","sources":["../../src/lib/utils/getUserFullName.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,QAAA,MAAM,eAAe,GAAI,gCAAgC,IAAI,KAAG,MAK/D,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"handleFormErrors.d.ts","sourceRoot":"","sources":["../../src/lib/utils/handleFormErrors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAI5C,QAAA,MAAM,gBAAgB,SAAU,IAAI,CAAC,GAAG,CAAC,SAAS,OAAO,KAAG,IAS3D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"handleFormErrors.d.ts","sourceRoot":"","sources":["../../src/lib/utils/handleFormErrors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAI5C,QAAA,MAAM,gBAAgB,GAAI,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,OAAO,KAAG,IAS3D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@os-team/profile",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "license": "UNLICENSED",
5
5
  "repository": "git@gitlab.com:os-team/libs/profile.git",
6
6
  "main": "./dist/index.js",
@@ -39,59 +39,59 @@
39
39
  "@types/react-dom": "^18.3.2"
40
40
  },
41
41
  "dependencies": {
42
- "@os-design/core": "^1.0.265",
43
- "@os-design/form": "^1.0.100",
44
- "@os-design/icons": "^1.0.68",
42
+ "@os-design/core": "^1.0.281",
43
+ "@os-design/form": "^1.0.116",
44
+ "@os-design/icons": "^1.0.69",
45
45
  "@os-design/media": "^1.0.32",
46
- "@os-design/styles": "^1.0.65",
47
- "@os-design/theming": "^1.0.61",
48
- "@os-design/utils": "^1.0.85",
46
+ "@os-design/styles": "^1.0.66",
47
+ "@os-design/theming": "^1.0.62",
48
+ "@os-design/utils": "^1.0.88",
49
49
  "@os-team/plural-forms": "^1.0.17"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@babel/cli": "^7.26.4",
53
- "@babel/core": "^7.26.0",
53
+ "@babel/core": "^7.26.9",
54
54
  "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
55
- "@babel/preset-env": "^7.26.0",
55
+ "@babel/preset-env": "^7.26.9",
56
56
  "@babel/preset-react": "^7.26.3",
57
57
  "@babel/preset-typescript": "^7.26.0",
58
- "@emotion/react": "^11.13.5",
58
+ "@emotion/react": "^11.14.0",
59
59
  "@emotion/serialize": "^1.3.3",
60
- "@emotion/styled": "^11.13.5",
60
+ "@emotion/styled": "^11.14.0",
61
61
  "@os-team/prettier-config": "1.2.8",
62
62
  "@os-team/relay-network-creator": "^1.3.3",
63
63
  "@os-team/relay-network-mw-upload": "^1.2.27",
64
- "@types/node": "^22.10.1",
64
+ "@types/node": "^22.13.9",
65
65
  "@types/react": "^18.3.14",
66
66
  "@types/react-dom": "^18.3.2",
67
67
  "@types/react-relay": "^18.2.0",
68
68
  "babel-plugin-relay": "^18.2.0",
69
69
  "cross-env": "^7.0.3",
70
- "eslint": "^9.16.0",
71
- "eslint-config-os-team-react": "1.2.28",
70
+ "eslint": "^9.21.0",
71
+ "eslint-config-os-team-react": "1.2.30",
72
72
  "get-graphql-schema": "^2.1.2",
73
- "graphql": "^16.9.0",
73
+ "graphql": "^16.10.0",
74
74
  "husky": "^9.1.7",
75
- "i18next": "^24.0.5",
76
- "i18next-browser-languagedetector": "^8.0.1",
77
- "i18next-http-backend": "^3.0.1",
75
+ "i18next": "^24.2.2",
76
+ "i18next-browser-languagedetector": "^8.0.4",
77
+ "i18next-http-backend": "^3.0.2",
78
78
  "lazysizes": "^5.3.2",
79
- "lint-staged": "^15.2.10",
79
+ "lint-staged": "^15.4.3",
80
80
  "npm-run-all": "^4.1.5",
81
- "prettier": "3.4.2",
81
+ "prettier": "3.5.3",
82
82
  "progress-bar-webpack-plugin": "^2.1.0",
83
83
  "react": "^18.3.1",
84
84
  "react-app-rewired": "^2.2.1",
85
85
  "react-dom": "^18.3.1",
86
- "react-i18next": "^15.1.3",
86
+ "react-i18next": "^15.4.1",
87
87
  "react-relay": "^18.2.0",
88
- "react-router": "^7.0.2",
88
+ "react-router": "^7.2.0",
89
89
  "react-scripts": "^5.0.1",
90
90
  "relay-compiler": "^18.2.0",
91
91
  "relay-runtime": "^18.2.0",
92
- "release-it": "^17.10.0",
92
+ "release-it": "^18.1.2",
93
93
  "rimraf": "^6.0.1",
94
- "typescript": "^5.7.2",
94
+ "typescript": "^5.8.2",
95
95
  "webpack-bundle-analyzer": "^4.10.2"
96
96
  },
97
97
  "peerDependencies": {
@@ -0,0 +1,170 @@
1
+ import {
2
+ Alert,
3
+ Form,
4
+ FormItem,
5
+ Input,
6
+ message,
7
+ Modal,
8
+ type ModalProps,
9
+ } from '@os-design/core';
10
+ import { FormProvider, useExistingForm, useForm } from '@os-design/form';
11
+ import graphql from 'babel-plugin-relay/macro';
12
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
13
+ import { useTranslation } from 'react-i18next';
14
+ import { useMutation } from 'react-relay';
15
+ import handleFormErrors from '../../utils/handleFormErrors';
16
+ import FormError from '../shared/FormError';
17
+ import getError from '../../utils/getError';
18
+ import type { ProfileDeleteAccountModalRequestMutation } from './__generated__/ProfileDeleteAccountModalRequestMutation.graphql';
19
+ import type { ProfileDeleteAccountModalConfirmMutation } from './__generated__/ProfileDeleteAccountModalConfirmMutation.graphql';
20
+
21
+ interface ProfileDeleteAccountFormData {
22
+ code: string;
23
+ }
24
+
25
+ const Step1Form: React.FC = () => {
26
+ const { t } = useTranslation(['profile']);
27
+
28
+ return (
29
+ <Alert type='info'>{t('profile:deleteAccountModal.requestAlert')}</Alert>
30
+ );
31
+ };
32
+
33
+ const Step2Form: React.FC = () => {
34
+ const { Field } = useExistingForm<ProfileDeleteAccountFormData>();
35
+ const { t } = useTranslation(['profile']);
36
+
37
+ const codeData = useMemo(
38
+ () => ({
39
+ label: t('profile:deleteAccountModal.code.label'),
40
+ placeholder: t('profile:deleteAccountModal.code.placeholder'),
41
+ }),
42
+ [t]
43
+ );
44
+
45
+ return (
46
+ <Form>
47
+ <Alert type='info'>{t('profile:deleteAccountModal.confirmAlert')}</Alert>
48
+
49
+ <Field
50
+ name='code'
51
+ data={codeData}
52
+ render={(props, { error }, data) => (
53
+ <FormItem label={data.label} error={error}>
54
+ <Input type='number' placeholder={data.placeholder} {...props} />
55
+ </FormItem>
56
+ )}
57
+ />
58
+
59
+ <FormError />
60
+ </Form>
61
+ );
62
+ };
63
+
64
+ interface ProfileDeleteAccountModalProps {
65
+ visible: boolean;
66
+ onClose: () => void;
67
+ }
68
+
69
+ const ProfileDeleteAccountModal: React.FC<ProfileDeleteAccountModalProps> = ({
70
+ visible,
71
+ onClose,
72
+ }) => {
73
+ const { t } = useTranslation(['profile']);
74
+ const [step, setStep] = useState(1);
75
+
76
+ const initValues = useMemo<ProfileDeleteAccountFormData>(
77
+ () => ({
78
+ code: '',
79
+ }),
80
+ []
81
+ );
82
+
83
+ const { form } = useForm(initValues);
84
+
85
+ // Reset the form when the modal is opened
86
+ useEffect(() => {
87
+ if (visible) {
88
+ form.reset();
89
+ setStep(1);
90
+ }
91
+ }, [form, visible]);
92
+
93
+ const [requestCommit, requestLoading] =
94
+ useMutation<ProfileDeleteAccountModalRequestMutation>(graphql`
95
+ mutation ProfileDeleteAccountModalRequestMutation {
96
+ requestDeleteAccount {
97
+ ok
98
+ }
99
+ }
100
+ `);
101
+
102
+ const [confirmCommit, confirmLoading] =
103
+ useMutation<ProfileDeleteAccountModalConfirmMutation>(graphql`
104
+ mutation ProfileDeleteAccountModalConfirmMutation(
105
+ $input: ConfirmDeleteAccountInput!
106
+ ) {
107
+ confirmDeleteAccount(input: $input) {
108
+ ok
109
+ }
110
+ }
111
+ `);
112
+
113
+ const onSubmitRequest = useCallback(() => {
114
+ requestCommit({
115
+ variables: {},
116
+ onError: (error) => message.error(getError(error).message),
117
+ onCompleted: () => setStep(2),
118
+ });
119
+ }, [requestCommit]);
120
+
121
+ const onSubmitConfirm = useCallback(() => {
122
+ confirmCommit({
123
+ variables: {
124
+ input: {
125
+ code: form.values.get('code'),
126
+ },
127
+ },
128
+ onError: (error) => handleFormErrors(form, error),
129
+ onCompleted: () => {
130
+ onClose();
131
+ window.location.href = '/auth/';
132
+ },
133
+ });
134
+ }, [confirmCommit, form, onClose]);
135
+
136
+ const modalProps = useMemo<ModalProps>(
137
+ () =>
138
+ step === 1
139
+ ? {
140
+ okText: t('profile:deleteAccountModal.requestButton'),
141
+ okLoading: requestLoading,
142
+ onOk: onSubmitRequest,
143
+ }
144
+ : {
145
+ okText: t('profile:deleteAccountModal.confirmButton'),
146
+ okLoading: confirmLoading,
147
+ onOk: onSubmitConfirm,
148
+ okDanger: true,
149
+ },
150
+ [confirmLoading, onSubmitConfirm, onSubmitRequest, requestLoading, step, t]
151
+ );
152
+
153
+ const children = useMemo(
154
+ () => (step === 1 ? <Step1Form /> : <Step2Form />),
155
+ [step]
156
+ );
157
+
158
+ return (
159
+ <Modal
160
+ title={t('profile:deleteAccountModal.title')}
161
+ visible={visible}
162
+ onClose={onClose}
163
+ {...modalProps}
164
+ >
165
+ <FormProvider form={form}>{children}</FormProvider>
166
+ </Modal>
167
+ );
168
+ };
169
+
170
+ export default ProfileDeleteAccountModal;
@@ -13,6 +13,7 @@ import ProfileUpdatePasswordModal from './ProfileUpdatePasswordModal';
13
13
  import UserAvatar from './UserAvatar';
14
14
  import { type ProfileDrawerContentSignOutMutation } from './__generated__/ProfileDrawerContentSignOutMutation.graphql';
15
15
  import { type ProfileDrawerContentUpdateAvatarMutation } from './__generated__/ProfileDrawerContentUpdateAvatarMutation.graphql';
16
+ import ProfileDeleteAccountModal from './ProfileDeleteAccountModal';
16
17
 
17
18
  export interface ProfileDrawerContentProps {
18
19
  /**
@@ -201,6 +202,24 @@ const ChangePasswordButton: React.FC = () => {
201
202
  );
202
203
  };
203
204
 
205
+ const DeleteAccountButton: React.FC = () => {
206
+ const { t } = useTranslation(['profile']);
207
+ const [modalVisible, setModalVisible] = useState(false);
208
+
209
+ return (
210
+ <>
211
+ <ProfileButton onClick={() => setModalVisible(true)}>
212
+ {t('profile:deleteAccount')}
213
+ </ProfileButton>
214
+
215
+ <ProfileDeleteAccountModal
216
+ visible={modalVisible}
217
+ onClose={() => setModalVisible(false)}
218
+ />
219
+ </>
220
+ );
221
+ };
222
+
204
223
  const SignOutButton: React.FC = () => {
205
224
  const { t } = useTranslation(['profile']);
206
225
 
@@ -261,6 +280,7 @@ const ProfileDrawerContent: React.FC<ProfileDrawerContentProps> = ({
261
280
 
262
281
  {actions}
263
282
 
283
+ <DeleteAccountButton />
264
284
  <SignOutButton />
265
285
 
266
286
  {children}
@@ -26,7 +26,7 @@ const StyledUserAvatar = styled(UserAvatar)`
26
26
 
27
27
  @media (hover: hover) {
28
28
  &:hover,
29
- &:focus {
29
+ &:focus-visible {
30
30
  opacity: 0.7;
31
31
  }
32
32
  ${transitionStyles('opacity')};
@@ -52,7 +52,6 @@ const UserAvatarAddon: React.FC<UserAvatarAddonProps> = ({
52
52
  onKeyDown={(e) => {
53
53
  if (e.key === 'Enter') onClick();
54
54
  }}
55
- onMouseDown={(e) => e.preventDefault()}
56
55
  {...rest}
57
56
  />
58
57
  </ThemeOverrider>
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @generated SignedSource<<d507b3267ba624a9d0277cf9e6c095dc>>
3
+ * @lightSyntaxTransform
4
+ * @nogrep
5
+ */
6
+
7
+ /* tslint:disable */
8
+ /* eslint-disable */
9
+ // @ts-nocheck
10
+
11
+ import { ConcreteRequest } from 'relay-runtime';
12
+ export type ConfirmDeleteAccountInput = {
13
+ code: string;
14
+ };
15
+ export type ProfileDeleteAccountModalConfirmMutation$variables = {
16
+ input: ConfirmDeleteAccountInput;
17
+ };
18
+ export type ProfileDeleteAccountModalConfirmMutation$data = {
19
+ readonly confirmDeleteAccount: {
20
+ readonly ok: boolean;
21
+ };
22
+ };
23
+ export type ProfileDeleteAccountModalConfirmMutation = {
24
+ response: ProfileDeleteAccountModalConfirmMutation$data;
25
+ variables: ProfileDeleteAccountModalConfirmMutation$variables;
26
+ };
27
+
28
+ const node: ConcreteRequest = (function(){
29
+ var v0 = [
30
+ {
31
+ "defaultValue": null,
32
+ "kind": "LocalArgument",
33
+ "name": "input"
34
+ }
35
+ ],
36
+ v1 = [
37
+ {
38
+ "alias": null,
39
+ "args": [
40
+ {
41
+ "kind": "Variable",
42
+ "name": "input",
43
+ "variableName": "input"
44
+ }
45
+ ],
46
+ "concreteType": "StatusPayload",
47
+ "kind": "LinkedField",
48
+ "name": "confirmDeleteAccount",
49
+ "plural": false,
50
+ "selections": [
51
+ {
52
+ "alias": null,
53
+ "args": null,
54
+ "kind": "ScalarField",
55
+ "name": "ok",
56
+ "storageKey": null
57
+ }
58
+ ],
59
+ "storageKey": null
60
+ }
61
+ ];
62
+ return {
63
+ "fragment": {
64
+ "argumentDefinitions": (v0/*: any*/),
65
+ "kind": "Fragment",
66
+ "metadata": null,
67
+ "name": "ProfileDeleteAccountModalConfirmMutation",
68
+ "selections": (v1/*: any*/),
69
+ "type": "Mutation",
70
+ "abstractKey": null
71
+ },
72
+ "kind": "Request",
73
+ "operation": {
74
+ "argumentDefinitions": (v0/*: any*/),
75
+ "kind": "Operation",
76
+ "name": "ProfileDeleteAccountModalConfirmMutation",
77
+ "selections": (v1/*: any*/)
78
+ },
79
+ "params": {
80
+ "cacheID": "3b50f27a2aeb5cad62d9dd9aea21c926",
81
+ "id": null,
82
+ "metadata": {},
83
+ "name": "ProfileDeleteAccountModalConfirmMutation",
84
+ "operationKind": "mutation",
85
+ "text": "mutation ProfileDeleteAccountModalConfirmMutation(\n $input: ConfirmDeleteAccountInput!\n) {\n confirmDeleteAccount(input: $input) {\n ok\n }\n}\n"
86
+ }
87
+ };
88
+ })();
89
+
90
+ (node as any).hash = "99038f6b8c389648b94a77aa065ff902";
91
+
92
+ export default node;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @generated SignedSource<<fcad4b832cf53f5a8f514b3dabdb210b>>
3
+ * @lightSyntaxTransform
4
+ * @nogrep
5
+ */
6
+
7
+ /* tslint:disable */
8
+ /* eslint-disable */
9
+ // @ts-nocheck
10
+
11
+ import { ConcreteRequest } from 'relay-runtime';
12
+ export type ProfileDeleteAccountModalRequestMutation$variables = Record<PropertyKey, never>;
13
+ export type ProfileDeleteAccountModalRequestMutation$data = {
14
+ readonly requestDeleteAccount: {
15
+ readonly ok: boolean;
16
+ };
17
+ };
18
+ export type ProfileDeleteAccountModalRequestMutation = {
19
+ response: ProfileDeleteAccountModalRequestMutation$data;
20
+ variables: ProfileDeleteAccountModalRequestMutation$variables;
21
+ };
22
+
23
+ const node: ConcreteRequest = (function(){
24
+ var v0 = [
25
+ {
26
+ "alias": null,
27
+ "args": null,
28
+ "concreteType": "StatusPayload",
29
+ "kind": "LinkedField",
30
+ "name": "requestDeleteAccount",
31
+ "plural": false,
32
+ "selections": [
33
+ {
34
+ "alias": null,
35
+ "args": null,
36
+ "kind": "ScalarField",
37
+ "name": "ok",
38
+ "storageKey": null
39
+ }
40
+ ],
41
+ "storageKey": null
42
+ }
43
+ ];
44
+ return {
45
+ "fragment": {
46
+ "argumentDefinitions": [],
47
+ "kind": "Fragment",
48
+ "metadata": null,
49
+ "name": "ProfileDeleteAccountModalRequestMutation",
50
+ "selections": (v0/*: any*/),
51
+ "type": "Mutation",
52
+ "abstractKey": null
53
+ },
54
+ "kind": "Request",
55
+ "operation": {
56
+ "argumentDefinitions": [],
57
+ "kind": "Operation",
58
+ "name": "ProfileDeleteAccountModalRequestMutation",
59
+ "selections": (v0/*: any*/)
60
+ },
61
+ "params": {
62
+ "cacheID": "cd42c1d7733a3434f5df551f574bc2e4",
63
+ "id": null,
64
+ "metadata": {},
65
+ "name": "ProfileDeleteAccountModalRequestMutation",
66
+ "operationKind": "mutation",
67
+ "text": "mutation ProfileDeleteAccountModalRequestMutation {\n requestDeleteAccount {\n ok\n }\n}\n"
68
+ }
69
+ };
70
+ })();
71
+
72
+ (node as any).hash = "cf5b3f55e2cd09b456ad657b90b72657";
73
+
74
+ export default node;
@@ -6,6 +6,7 @@ interface Constraint {
6
6
  interface ErrorObject {
7
7
  code: string;
8
8
  message: string;
9
+ extensions?: Record<string, unknown>;
9
10
  data?: Record<string, Constraint>;
10
11
  }
11
12
 
@@ -88,14 +89,28 @@ const getError = (error: unknown): ErrorObject => {
88
89
  return {
89
90
  code: firstError.extensions.code,
90
91
  message: firstError.message,
92
+ extensions: firstError.extensions,
91
93
  };
92
94
  }
93
95
 
94
96
  return {
95
97
  code: firstError.extensions.code,
96
98
  message: firstError.message,
99
+ extensions: firstError.extensions,
97
100
  data: firstError.extensions.data,
98
101
  };
99
102
  };
100
103
 
104
+ export const getErrorMessage = (error: unknown): string => {
105
+ const err = getError(error);
106
+ let msg = err.message;
107
+ if (err.data) {
108
+ const constraints = Object.values(err.data);
109
+ if (constraints.length > 0) {
110
+ msg = constraints[0].message;
111
+ }
112
+ }
113
+ return msg;
114
+ };
115
+
101
116
  export default getError;
@@ -401,6 +401,10 @@ input CompleteUserVideoStepInput {
401
401
  id: ID!
402
402
  }
403
403
 
404
+ input ConfirmDeleteAccountInput {
405
+ code: String!
406
+ }
407
+
404
408
  input ConfirmEmailInput {
405
409
  password: String!
406
410
  token: String!
@@ -797,6 +801,8 @@ type Mutation {
797
801
  signOut: StatusPayload!
798
802
  updateProfile(input: UpdateProfileInput!): User!
799
803
  updatePassword(input: UpdatePasswordInput!): User!
804
+ requestDeleteAccount: StatusPayload!
805
+ confirmDeleteAccount(input: ConfirmDeleteAccountInput!): StatusPayload!
800
806
  destroySession(input: DestroySessionInput!): StatusPayload!
801
807
  destroyAllOtherSessions: StatusPayload!
802
808
  createBlogLanguage(input: CreateBlogLanguageInput!): BlogLanguage!
@@ -832,7 +838,6 @@ type Mutation {
832
838
  createLesson(input: CreateLessonInput!): Lesson!
833
839
  checkAnswer(input: CheckAnswerInput!): CheckAnswerPayload!
834
840
  updateAvatar(input: UpdateAvatarInput!): User!
835
- deleteAccount: StatusPayload!
836
841
  updateSettings(input: UpdateSettingsInput!): Settings!
837
842
  createTestTag(input: CreateTestTagInput!): TestTag!
838
843
  updateTestTag(input: UpdateTestTagInput!): TestTag!
@@ -2195,6 +2200,11 @@ type User implements Node {
2195
2200
  {"en":"The date of the last update of the object.","ru":"Дата последнего обновления объекта."}
2196
2201
  """
2197
2202
  updatedAt: Long!
2203
+
2204
+ """
2205
+ {"en":"The date the object was deleted.","ru":"Дата удаления объекта."}
2206
+ """
2207
+ deletedAt: Long
2198
2208
  email: String!
2199
2209
  passwordHash: String
2200
2210
  firstName: String
@@ -6,6 +6,7 @@ interface Constraint {
6
6
  interface ErrorObject {
7
7
  code: string;
8
8
  message: string;
9
+ extensions?: Record<string, unknown>;
9
10
  data?: Record<string, Constraint>;
10
11
  }
11
12
 
@@ -88,14 +89,28 @@ const getError = (error: unknown): ErrorObject => {
88
89
  return {
89
90
  code: firstError.extensions.code,
90
91
  message: firstError.message,
92
+ extensions: firstError.extensions,
91
93
  };
92
94
  }
93
95
 
94
96
  return {
95
97
  code: firstError.extensions.code,
96
98
  message: firstError.message,
99
+ extensions: firstError.extensions,
97
100
  data: firstError.extensions.data,
98
101
  };
99
102
  };
100
103
 
104
+ export const getErrorMessage = (error: unknown): string => {
105
+ const err = getError(error);
106
+ let msg = err.message;
107
+ if (err.data) {
108
+ const constraints = Object.values(err.data);
109
+ if (constraints.length > 0) {
110
+ msg = constraints[0].message;
111
+ }
112
+ }
113
+ return msg;
114
+ };
115
+
101
116
  export default getError;