Browse Source

Setting a memo

Leszek Wiesner 4 years ago
parent
commit
b2f8e2415b

+ 3 - 0
pioneer/packages/apps-routing/src/index.ts

@@ -18,6 +18,7 @@ import storage from './storage';
 import sudo from './sudo';
 import toolbox from './toolbox';
 import transfer from './transfer';
+import memo from './memo';
 // Joy packages
 import members from './joy-members';
 import { terms, privacyPolicy } from './joy-pages';
@@ -40,6 +41,7 @@ export default function create (t: <T = string> (key: string, text: string, opti
       null,
       transfer(t),
       accounts(t),
+      memo(t),
       settings(t),
       // Those are hidden
       terms(t),
@@ -56,6 +58,7 @@ export default function create (t: <T = string> (key: string, text: string, opti
       null,
       transfer(t),
       accounts(t),
+      memo(t),
       settings(t),
       null,
       explorer(t),

+ 20 - 0
pioneer/packages/apps-routing/src/memo.ts

@@ -0,0 +1,20 @@
+import { Route } from './types';
+
+import { MemoModal } from '@polkadot/joy-utils/react/components/Memo';
+
+export default function create (t: <T = string> (key: string, text: string, options: { ns: string }) => T): Route {
+  return {
+    // Assert to get around the uncecessary requirement for RouteProps
+    Component: MemoModal as React.ComponentType<any>,
+    Modal: MemoModal,
+    display: {
+      isHidden: false,
+      needsApi: [
+        'tx.memo.updateMemo'
+      ]
+    },
+    icon: 'sticky-note',
+    name: 'memo',
+    text: t<string>('nav.memo', 'My memo', { ns: 'apps-routing' })
+  };
+}

+ 67 - 0
pioneer/packages/joy-utils/src/react/components/Memo.tsx

@@ -0,0 +1,67 @@
+import React, { useState, useEffect } from 'react';
+import { useApi, useCall } from '@polkadot/react-hooks';
+import { Text } from '@polkadot/types';
+import { u32 } from '@polkadot/types/primitive';
+import { Form, TextArea, Modal } from 'semantic-ui-react';
+import { Loading } from './PromiseComponent';
+import TxButton from './TxButton';
+import { useMyAccount } from '../hooks';
+
+export function MemoForm () {
+  const { isApiReady, api } = useApi();
+  const { state: { address } } = useMyAccount();
+  const storedMemo = useCall<Text>(isApiReady && api.query.memo.memo, [address]);
+  const maxMemoLength = useCall<u32>(isApiReady && api.query.memo.maxMemoLength, []);
+  const [memo, setMemo] = useState<string | undefined>(undefined);
+  const isMemoDifferent = memo?.toString() !== storedMemo?.toString();
+
+  useEffect(() => {
+    if (storedMemo) {
+      setMemo(storedMemo.toString());
+    }
+  }, [storedMemo?.toString()]);
+
+  return memo !== undefined
+    ? (
+      <Form style={{ width: '100%' }}>
+        <Form.Field>
+          <TextArea
+            rows={3}
+            label='Memo (supports Markdown):'
+            placeholder='Here you can type any public information relevant to your account.'
+            value={memo}
+            onChange={(e, props) => setMemo(props.value?.toString() || '')}
+            maxLength={maxMemoLength}
+          />
+        </Form.Field>
+        <TxButton
+          isDisabled={!isMemoDifferent}
+          label='Update memo'
+          params={[memo]}
+          tx='memo.updateMemo'
+        />
+      </Form>
+    )
+    : <Loading text={'Fetching current memo...'} />;
+}
+
+interface MemoModalProps {
+  onClose: () => void;
+}
+
+export function MemoModal ({ onClose }: MemoModalProps) {
+  return (
+    <Modal
+      size='small'
+      open
+      closeIcon
+      closeOnDimmerClick={true}
+      style={{ marginTop: '30px' }}
+      onClose={onClose}>
+      <Modal.Header>Update memo</Modal.Header>
+      <Modal.Content>
+        <MemoForm />
+      </Modal.Content>
+    </Modal>
+  );
+}