diff --git a/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx b/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx
index dd20c3c2d..a85eacd2c 100644
--- a/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx
+++ b/packages/examples/sdk-frontend-react/src/app/ChatUITest/ChatViewComponent.tsx
@@ -15,7 +15,7 @@ const ChatViewComponentTest = () => {
Chat UI Test page
{/* {console.log('in close')}} /> */}
- console.log("BOIIII RETURNNNSSSSS")} chatId='4ac5ab85c9c3d57adbdf2dba79357e56b2f9ef0256befe750d9f93af78d2ca68' limit={10} isConnected={true} />
+ console.log("BOIIII RETURNNNSSSSS")} chatId='5b3dba72949b77c48fe12cf87ffab91309ed9d1d78dec1db17c254020d2ffe2b' limit={10} isConnected={true} />
);
diff --git a/packages/uiweb/package.json b/packages/uiweb/package.json
index 6645e2d69..7dfa3a9c3 100644
--- a/packages/uiweb/package.json
+++ b/packages/uiweb/package.json
@@ -25,6 +25,8 @@
"livekit-client": "^1.13.3",
"moment": "^2.29.4",
"react-icons": "^4.10.1",
+ "react-easy-crop": "^4.1.4",
+ "react-image-file-resizer": "^0.4.7",
"react-toastify": "^9.1.3",
"react-twitter-embed": "^4.0.4",
"uuid": "^9.0.1"
@@ -33,6 +35,6 @@
"@pushprotocol/restapi": "^1.2.15",
"@pushprotocol/socket": "^0.5.0",
"react": ">=16.8.0",
- "styled-components": "^5.3.5"
+ "styled-components": "^6.0.8"
}
}
diff --git a/packages/uiweb/src/lib/components/chat/ChatProfile/GroupInfoModal.tsx b/packages/uiweb/src/lib/components/chat/ChatProfile/GroupInfoModal.tsx
index e1c8d3f62..e738232d1 100644
--- a/packages/uiweb/src/lib/components/chat/ChatProfile/GroupInfoModal.tsx
+++ b/packages/uiweb/src/lib/components/chat/ChatProfile/GroupInfoModal.tsx
@@ -31,17 +31,11 @@ import addIcon from '../../../icons/addicon.svg';
import DismissAdmin from '../../../icons/dismissadmin.svg';
import AddAdmin from '../../../icons/addadmin.svg';
import Remove from '../../../icons/remove.svg';
-import { shortenText } from '../../../helpers';
+import { copyToClipboard, shortenText } from '../../../helpers';
import TokenGatedIcon from '../../../icons/TokenGatedIcon.svg';
import ConditionsComponent from '../CreateGroup/ConditionsComponent';
-import { ConditionArray } from '../exportedTypes';
import { ACCESS_TYPE_TITLE, OPERATOR_OPTIONS_INFO } from '../constants';
-import * as PushAPI from '@pushprotocol/restapi';
-import { Rule } from '../types';
-import {
- GroupRulesType,
- getRuleInfo,
-} from '../helpers/getRulesToCondtionArray';
+import { getRuleInfo } from '../helpers/getRulesToCondtionArray';
const UPDATE_KEYS = {
REMOVE_MEMBER: 'REMOVE_MEMBER',
@@ -95,10 +89,14 @@ const PendingMembers = ({
{showPendingRequests && (
-
{groupInfo?.pendingMembers &&
@@ -120,7 +118,7 @@ const PendingMembers = ({
/>
))}
-
+
)}
);
@@ -148,7 +146,7 @@ export const ConditionsInformation = ({
return null;
};
- console.log(groupRules);
+
return (
(
-
+
{ACCESS_TYPE_TITLE[key as keyof typeof ACCESS_TYPE_TITLE]?.heading}
- {getOperator(key as keyof typeof groupRules) ? (
+
{
OPERATOR_OPTIONS_INFO[
@@ -193,14 +193,17 @@ export const ConditionsInformation = ({
}
+ >
) : null}
(false);
const [memberList, setMemberList] = useState([]);
const [isLoading, setIsLoading] = useState(false);
+ const [copyText, setCopyText] = useState('');
const [selectedMemberAddress, setSelectedMemberAddress] = useState<
string | null
>(null);
@@ -485,13 +489,56 @@ const GroupInformation = ({
return (
+
+
+ Chat ID
+
+ {
+ copyToClipboard(groupInfo?.chatId);
+ setCopyText('copied');
+ }}
+ onMouseEnter={() => {
+ setCopyText('click to copy');
+ }}
+ onMouseLeave={() => {
+ setCopyText('');
+ }}
+ >
+
+ {shortenText(groupInfo?.chatId, 8, true)}
+
+ {!!copyText && (
+
+ {copyText}
+
+ )}
+
+
Group Description
{groupInfo?.groupDescription}
@@ -557,36 +604,35 @@ const GroupInformation = ({
)}
-
-
- {groupInfo?.members &&
- groupInfo?.members?.length > 0 &&
- groupInfo?.members.map((item, index) => (
-
- ))}
-
-
+ {groupInfo?.members &&
+ groupInfo?.members?.length > 0 &&
+ groupInfo?.members.map((item, index) => (
+
+ ))}
+
{showAddMoreWalletModal && (
(null);
- const { updateGroup } = useUpdateGroup();
const isMobile = useMediaQuery(device.mobileL);
const dropdownRef = useRef(null);
useClickAway(dropdownRef, () => setSelectedMemberAddress(null));
- type UpdateGroupType = {
- adminList: Array;
- memberList: Array;
- };
-
- const handleUpdateGroup = async (options: UpdateGroupType) => {
- const { adminList, memberList } = options || {};
- const updateResponse = await updateGroup({
- groupInfo,
- memberList,
- adminList,
- });
- return { updateResponse };
- };
-
const onClose = (): void => {
setModal(false);
};
@@ -706,11 +736,16 @@ export const GroupInfoModal = ({
/>
-
+
{groupInfo?.groupName}
{groupInfo?.members?.length} Members
@@ -737,7 +772,7 @@ const GroupHeader = styled.div`
`;
const GroupDescription = styled.div`
- margin-top: 34px;
+ margin-top: 25px;
display: flex;
flex-direction: column;
width: 100%;
@@ -837,4 +872,18 @@ const ConditionSection = styled(Section)<{ theme: IChatTheme }>`
}
`;
+const ProfileSection = styled(Section)<{ theme: IChatTheme }>`
+ &::-webkit-scrollbar-thumb {
+ background: ${(props) => props.theme.scrollbarColor};
+ border-radius: 10px;
+ }
+ &::-webkit-scrollbar-button {
+ height: 40px;
+ }
+
+ &::-webkit-scrollbar {
+ width: 4px;
+ }
+`;
+
//auto update members when an user accepts not done
diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/AutoImageClipper.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/AutoImageClipper.tsx
new file mode 100644
index 000000000..a0cc9b49b
--- /dev/null
+++ b/packages/uiweb/src/lib/components/chat/CreateGroup/AutoImageClipper.tsx
@@ -0,0 +1,148 @@
+// React + Web3 Essentials
+import React, { Fragment, useCallback, useState } from "react";
+
+// External Packages
+import Cropper from "react-easy-crop";
+import styledComponents from "styled-components";
+import Resizer from "react-image-file-resizer";
+
+type CropType = {
+ x: number;
+ y: number;
+}
+
+type CroppedAreaPixels = {
+ height: number;
+ width: number;
+ x: number;
+ y: number;
+}
+
+const AutoImageClipper = (props: { imageSrc: any; onImageCropped: any; width: any; height: any; }) => {
+ const { imageSrc, onImageCropped, width, height } = props;
+ const [crop, setCrop] = useState({ x: 0, y: 0 });
+ const [zoom, setZoom] = useState(1);
+ const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
+ const [croppedImage, setCroppedImage] = useState('');
+ const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
+ setCroppedAreaPixels(croppedAreaPixels);
+ }, []);
+
+ React.useEffect(() => {
+ async function showCroppedImage() {
+ try {
+ if (imageSrc) {
+ const croppedImage = await getCroppedImg(imageSrc, croppedAreaPixels!);
+ const image = await resizeFile(croppedImage);
+ onImageCropped(image);
+ } else {
+ return "Nothing";
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ showCroppedImage();
+ }, [crop]);
+
+ async function getCroppedImg(imageSrc:string, pixelCrop: { height: any; width: any; x: any; y: any; }) {
+ const image = await createImage(imageSrc);
+ const canvas = document.createElement("canvas");
+ canvas.width = pixelCrop?.width;
+ canvas.height = pixelCrop?.height;
+ const ctx = canvas.getContext("2d");
+ const fileName = "none.jpg";
+
+ ctx!.drawImage(
+ image as CanvasImageSource,
+ pixelCrop.x,
+ pixelCrop.y,
+ pixelCrop.width,
+ pixelCrop.height,
+ 0,
+ 0,
+ pixelCrop.width,
+ pixelCrop.height
+ );
+
+ // As Base64 string
+ // return canvas.toDataURL('image/jpeg');
+
+ // As a blob
+ return new Promise((resolve, reject) => {
+ canvas.toBlob((file) => {
+ // resolve(URL.createObjectURL(file));
+ resolve(
+ new File([file!], fileName, {
+ type: "image/jpeg",
+ lastModified: Date.now()
+ })
+ );
+ }, "image/jpeg");
+ });
+ }
+
+ const resizeFile = (file: any) => {
+ return new Promise((resolve) => {
+ Resizer.imageFileResizer(
+ file,
+ 128,
+ 128,
+ "JPEG",
+ 80,
+ 0,
+ (uri) => {
+ resolve(uri);
+ setCroppedImage(uri as unknown as string);
+ },
+ "base64"
+ );
+ });
+ };
+
+ const createImage = (url: string) => {
+ return new Promise((resolve, reject) => {
+ const image = new Image();
+ image.addEventListener("load", () => resolve(image));
+ image.addEventListener("error", (error) => reject(error));
+ image.setAttribute("crossOrigin", "anonymous"); // needed to avoid cross-origin issues on CodeSandbox
+ image.src = url;
+ });
+ };
+
+ const onZoomChange = (zoom: React.SetStateAction) => {
+ setZoom(zoom);
+ };
+ return (
+
+
+
+
+
+ );
+};
+
+const Container = styledComponents.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ `;
+
+export default AutoImageClipper;
diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx
index 49add35d8..847018da8 100644
--- a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx
+++ b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupModal.tsx
@@ -27,6 +27,7 @@ import {
import { Image } from '../../../config/styles';
import { ProfilePicture, device } from '../../../config';
import { CriteriaValidationErrorType } from '../types';
+import AutoImageClipper from './AutoImageClipper';
export const CREATE_GROUP_STEP_KEYS = {
INPUT_DETAILS: 1,
@@ -71,11 +72,14 @@ export const CreateGroupModal: React.FC = ({
}, [activeComponent]);
const useDummyGroupInfo = false;
- const [groupInputDetails, setGroupInputDetails] = useState({
- groupName: useDummyGroupInfo ? 'This is duumy group name' : '',
- groupDescription: useDummyGroupInfo ? 'This is dummy group description for testing' : '',
- groupImage: useDummyGroupInfo ? ProfilePicture : ''
- })
+ const [groupInputDetails, setGroupInputDetails] =
+ useState({
+ groupName: useDummyGroupInfo ? 'This is duumy group name' : '',
+ groupDescription: useDummyGroupInfo
+ ? 'This is dummy group description for testing'
+ : '',
+ groupImage: useDummyGroupInfo ? ProfilePicture : '',
+ });
const renderComponent = () => {
switch (activeComponent) {
@@ -167,6 +171,8 @@ const CreateGroupDetail = ({
useState({});
const fileUploadInputRef = useRef(null);
const isMobile = useMediaQuery(device.mobileL);
+ const [isImageUploaded, setIsImageUploaded] = useState(false);
+ const [imageSrc, setImageSrc] = useState();
const handleChange = (e: Event) => {
if (!(e.target instanceof HTMLInputElement)) {
@@ -179,15 +185,22 @@ const CreateGroupDetail = ({
(e.target as HTMLInputElement).files &&
((e.target as HTMLInputElement).files as FileList).length
) {
+ setIsImageUploaded(true);
+ setGroupInputDetails({
+ groupDescription,
+ groupName,
+ groupImage: '',
+ });
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onloadend = function () {
- setGroupInputDetails({
- groupDescription,
- groupName,
- groupImage: reader.result as string,
- });
+ setImageSrc(reader.result as string);
+ // setGroupInputDetails({
+ // groupDescription,
+ // groupName,
+ // groupImage: reader.result as string,
+ // });
};
}
};
@@ -220,7 +233,6 @@ const CreateGroupDetail = ({
});
return;
}
-
}
if (handleNext) {
@@ -245,22 +257,37 @@ const CreateGroupDetail = ({
- {!groupImage && (
+ {isImageUploaded ? (
+ groupImage ? (
+
+
+
+ ) : (
+
+ setGroupInputDetails({
+ groupDescription,
+ groupName,
+ groupImage: croppedImage,
+ })
+ }
+ width={undefined}
+ height={undefined}
+ />
+ )
+ ) : (
)}
- {groupImage && (
-
-
-
- )}
+
{
//use the theme
const UploadContainer = styled.div`
width: fit-content;
+ min-width:128px;
+ min-height:128px;
cursor: pointer;
align-self: center;
`;
const ImageContainer = styled.div<{ theme: IChatTheme }>`
margin-top: 10px;
- width: fit-content;
cursor: pointer;
border-radius: 32px;
background: ${(props) => props.theme.backgroundColor.modalHoverBackground};
- padding: 40px;
+ width: 128px;
+ cursor: pointer;
+ height: 128px;
+ max-height: 128px;
+ display:flex;
+ align-items:center;
+ justify-content:center;
`;
const UpdatedImageContainer = styled.div`
margin-top: 10px;
- width: 112px;
+ width: 128px;
cursor: pointer;
- height: 112px;
+ height: 128px;
overflow: hidden;
+ max-height: 128px;
border-radius: 32px;
`;
diff --git a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx
index ba70ae396..45b7f09a7 100644
--- a/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx
+++ b/packages/uiweb/src/lib/components/chat/CreateGroup/CreateGroupType.tsx
@@ -28,13 +28,13 @@ import { ProfilePicture } from '../../../config';
const GROUP_TYPE_OPTIONS: Array = [
{
- heading: 'Open',
- subHeading: 'Anyone can join',
+ heading: 'Public',
+ subHeading: 'Anyone can view chats, even without joining',
value: 'open',
},
{
- heading: 'Encrypted',
- subHeading: 'Users must join group to view',
+ heading: 'Private',
+ subHeading: 'Encrypted Chats, Users must join group to view',
value: 'encrypted',
},
];
diff --git a/packages/uiweb/src/lib/components/chat/helpers/getRulesToCondtionArray.ts b/packages/uiweb/src/lib/components/chat/helpers/getRulesToCondtionArray.ts
index fab522e9c..c24da7465 100644
--- a/packages/uiweb/src/lib/components/chat/helpers/getRulesToCondtionArray.ts
+++ b/packages/uiweb/src/lib/components/chat/helpers/getRulesToCondtionArray.ts
@@ -18,8 +18,8 @@ export const getRuleInfo = (
}
const [chatRules, entryRules] = [
- getRulesToCondtionArray(rules.entry),
getRulesToCondtionArray(rules.chat),
+ getRulesToCondtionArray(rules.entry),
];
return {
diff --git a/packages/uiweb/src/lib/components/chat/reusables/OptionButtons.tsx b/packages/uiweb/src/lib/components/chat/reusables/OptionButtons.tsx
index 54762aeaf..6a64adb36 100644
--- a/packages/uiweb/src/lib/components/chat/reusables/OptionButtons.tsx
+++ b/packages/uiweb/src/lib/components/chat/reusables/OptionButtons.tsx
@@ -48,6 +48,8 @@ const OptionDescripton = ({ heading, subHeading,value }: OptionDescription) => {
color={theme.textColor?.modalSubHeadingText}
fontWeight="400"
fontSize="12px"
+ width='132px'
+ lineHeight='130%'
>
{subHeading}