diff --git a/src/app/organisms/emoji-verification/EmojiVerification.jsx b/src/app/organisms/emoji-verification/EmojiVerification.jsx
new file mode 100644
index 0000000..f56a467
--- /dev/null
+++ b/src/app/organisms/emoji-verification/EmojiVerification.jsx
@@ -0,0 +1,153 @@
+/* eslint-disable react/prop-types */
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+import './EmojiVerification.scss';
+import { twemojify } from '../../../util/twemojify';
+
+import initMatrix from '../../../client/initMatrix';
+import cons from '../../../client/state/cons';
+import navigation from '../../../client/state/navigation';
+
+import Text from '../../atoms/text/Text';
+import IconButton from '../../atoms/button/IconButton';
+import Button from '../../atoms/button/Button';
+import Spinner from '../../atoms/spinner/Spinner';
+import Dialog from '../../molecules/dialog/Dialog';
+
+import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
+import { useStore } from '../../hooks/useStore';
+
+function EmojiVerificationContent({ request, requestClose }) {
+ const [sas, setSas] = useState(null);
+ const [process, setProcess] = useState(false);
+ const mountStore = useStore();
+ mountStore.setItem(true);
+
+ const handleChange = () => {
+ if (request.done || request.cancelled) requestClose();
+ };
+
+ useEffect(() => {
+ mountStore.setItem(true);
+ if (request === null) return null;
+ const req = request;
+ req.on('change', handleChange);
+ return () => req.off('change', handleChange);
+ }, [request]);
+
+ const acceptRequest = async () => {
+ setProcess(true);
+ await request.accept();
+
+ const verifier = request.beginKeyVerification('m.sas.v1');
+ verifier.on('show_sas', (data) => {
+ if (!mountStore.getItem()) return;
+ setSas(data);
+ setProcess(false);
+ });
+ await verifier.verify();
+ };
+
+ const sasMismatch = () => {
+ sas.mismatch();
+ setProcess(true);
+ };
+
+ const sasConfirm = () => {
+ sas.confirm();
+ setProcess(true);
+ };
+
+ const renderWait = () => (
+ <>
+