Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(component): implemented a copy link button for copying invited c… #645

Merged
merged 12 commits into from
Jan 18, 2025

Conversation

pheobeayo
Copy link
Contributor

…odes

Description

implemented invited code links in button

implemented invited code links in button

Related Issue

Issue #635

#635 (comment)

Does this introduce a breaking change?

  • Yes
  • [ No] No

Other information

Copy link

vercel bot commented Dec 17, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
bandada-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 17, 2025 4:22pm
bandada-website ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 17, 2025 4:22pm

Copy link
Member

@vplasencia vplasencia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @pheobeayo! Thank you very much for this PR.

It looks great, but it would be nice to move the new invite code box to the modal that opens after clicking the Add member button. The issue description can help but feel free to ask any questions you may have.

@pheobeayo
Copy link
Contributor Author

Hey @pheobeayo! Thank you very much for this PR.

It looks great, but it would be nice to move the new invite code box to the modal that opens after clicking the Add member button. The issue description can help but feel free to ask any questions you may have.

Kindly review the changes made please

@vplasencia
Copy link
Member

Hey @pheobeayo! I will review the PR as soon as possible. Thank you!

@vplasencia
Copy link
Member

Hey @pheobeayo! Could you update your branch with the latest changes of the main branch and fix the branch conflict? Please, let me know if you need any help to do it.

@pheobeayo
Copy link
Contributor Author

Hey @pheobeayo! Could you update your branch with the latest changes of the main branch and fix the branch conflict? Please, let me know if you need any help to do it.

Fixed @vplasencia

Copy link
Member

@vplasencia vplasencia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @pheobeayo! Thank you very much for the updates.

The idea of this implementation is correct but this feature should be implemented inside the add-member-modal.tsx file.

The new additions would be something like:

    const {
        hasCopied: hasCopiedInviteCode,
        value: inviteCode,
        setValue: setInviteCode,
        onCopy: onCopyInviteCode
    } = useClipboard("")
        const generateInviteLink = useCallback(async () => {
        const inviteLink = await bandadaAPI.generateMagicLink(group.id)

        if (inviteLink === null) {
            return
        }

        setClientLink(inviteLink)
        const index = inviteLink.lastIndexOf("=")
        const inviteCodeLink = inviteLink.substring(index + 1)
        setInviteCode(inviteCodeLink)
    }, [group, setClientLink, setInviteCode])

UI code updates:

                                {!group.credentials && (
                                <>
                                    <Text mb="10px" color="balticSea.800">
                                        Share invite code
                                    </Text>

                                    <InputGroup size="lg">
                                        <Input
                                            pr="50px"
                                            placeholder="Invite code"
                                            value={inviteCode}
                                            isDisabled
                                        />
                                        <InputRightElement mr="5px">
                                            <Tooltip
                                                label={
                                                    hasCopiedInviteCode
                                                        ? "Copied!"
                                                        : "Copy"
                                                }
                                                closeOnClick={false}
                                                hasArrow
                                            >
                                                <IconButton
                                                    variant="link"
                                                    aria-label="Copy invite link"
                                                    onClick={onCopyInviteCode}
                                                    onMouseDown={(e) =>
                                                        e.preventDefault()
                                                    }
                                                    icon={
                                                        <Icon
                                                            color="sunsetOrange.600"
                                                            boxSize="5"
                                                            as={FiCopy}
                                                        />
                                                    }
                                                />
                                            </Tooltip>
                                        </InputRightElement>
                                    </InputGroup>
                                </>
                            )}

The final file would be something like:

import { getSemaphoreContract } from "@bandada/utils"
import {
    AbsoluteCenter,
    Box,
    Button,
    Divider,
    Heading,
    Icon,
    IconButton,
    Input,
    InputGroup,
    InputRightElement,
    Modal,
    ModalBody,
    ModalContent,
    ModalOverlay,
    Text,
    Textarea,
    Tooltip,
    useClipboard
} from "@chakra-ui/react"
import { useCallback, useEffect, useState } from "react"
import { FiCopy } from "react-icons/fi"
import { useSigner } from "wagmi"
import * as bandadaAPI from "../api/bandadaAPI"
import { Group } from "../types"
import parseMemberIds from "../utils/parseMemberIds"

export type AddMemberModalProps = {
    isOpen: boolean
    onClose: (value?: string[]) => void
    group: Group
}

export default function AddMemberModal({
    isOpen,
    onClose,
    group
}: AddMemberModalProps): JSX.Element {
    const [_memberIds, setMemberIds] = useState<string>("")
    const [_isLoading, setIsLoading] = useState(false)
    const {
        hasCopied,
        value: _clientLink,
        setValue: setClientLink,
        onCopy
    } = useClipboard("")
    const {
        hasCopied: hasCopiedInviteCode,
        value: inviteCode,
        setValue: setInviteCode,
        onCopy: onCopyInviteCode
    } = useClipboard("")
    const { data: signer } = useSigner()

    useEffect(() => {
        setMemberIds("")

        if (group.credentials) {
            setClientLink(
                `${import.meta.env.VITE_CLIENT_URL}?credentialGroupId=${
                    group.id
                }`
            )
        }
    }, [group, setClientLink])

    const addMember = useCallback(async () => {
        const memberIds = parseMemberIds(_memberIds)
        if (memberIds.length === 0) {
            alert("Please enter at least one member id!")
            return
        }

        const uniqueMemberIds = new Set(memberIds)
        if (uniqueMemberIds.size !== memberIds.length) {
            alert("Please ensure there are no repeated member IDs!")
            return
        }
        if (group.type === "on-chain" && group.members) {
            const existingMembers = new Set(
                group.members.map((memberId) => BigInt(memberId))
            )

            const conflictingMembers = []

            for (const memberId of memberIds) {
                const parsedMemberId = BigInt(memberId)

                if (existingMembers.has(parsedMemberId)) {
                    conflictingMembers.push(parsedMemberId)
                }
            }

            if (conflictingMembers.length > 0) {
                if (conflictingMembers.length === 1) {
                    alert(
                        `Member ID ${conflictingMembers[0]} already exists in the group.`
                    )
                } else {
                    alert(
                        `Member IDs ${conflictingMembers.join(
                            ", "
                        )} already exist in the group.`
                    )
                }
                return
            }
        }

        const confirmMessage = `
Are you sure you want to add the following members?
${memberIds.join("\n")}
        `

        if (!window.confirm(confirmMessage)) {
            return
        }

        setIsLoading(true)

        if (group.type === "off-chain") {
            if ((await bandadaAPI.addMembers(group.id, memberIds)) === null) {
                setIsLoading(false)
                return
            }

            setIsLoading(false)
            onClose(memberIds)
        } else {
            if (!signer) {
                alert("No valid signer for your transaction!")

                setIsLoading(false)
                return
            }

            try {
                const semaphore = getSemaphoreContract("sepolia", signer as any)

                await semaphore.addMembers(group.id, memberIds)

                setIsLoading(false)
                onClose(memberIds)
            } catch (error) {
                alert(
                    "Some error occurred! Check if you're on Sepolia network and the transaction is signed and completed"
                )

                setIsLoading(false)
            }
        }
    }, [onClose, _memberIds, group, signer])

    const generateInviteLink = useCallback(async () => {
        const inviteLink = await bandadaAPI.generateMagicLink(group.id)

        if (inviteLink === null) {
            return
        }

        setClientLink(inviteLink)
        const index = inviteLink.lastIndexOf("=")
        const inviteCodeLink = inviteLink.substring(index + 1)
        setInviteCode(inviteCodeLink)
    }, [group, setClientLink, setInviteCode])

    return (
        <Modal
            isOpen={isOpen}
            onClose={onClose}
            closeOnOverlayClick={false}
            isCentered
        >
            <ModalOverlay />
            <ModalContent bgColor="balticSea.50" maxW="450px">
                <ModalBody p="25px 30px">
                    <Heading fontSize="25px" fontWeight="500" mb="25px" as="h1">
                        New member
                    </Heading>

                    {!group.credentials && (
                        <Box mb="5px">
                            <Text my="10px" color="balticSea.800">
                                Add member IDs
                            </Text>

                            <Textarea
                                placeholder="Paste one or more member IDs separated by commas, spaces, or newlines"
                                size="lg"
                                value={_memberIds}
                                onChange={(event) =>
                                    setMemberIds(event.target.value)
                                }
                                rows={5}
                            />

                            <Button
                                my="10px"
                                width="100%"
                                variant="solid"
                                colorScheme="tertiary"
                                onClick={addMember}
                                isLoading={_isLoading}
                            >
                                Add members
                            </Button>
                        </Box>
                    )}

                    {group.type === "off-chain" && !group.credentials && (
                        <Box position="relative" py="8">
                            <Divider borderColor="balticSea.300" />
                            <AbsoluteCenter
                                fontSize="13px"
                                px="4"
                                bgColor="balticSea.50"
                            >
                                OR
                            </AbsoluteCenter>
                        </Box>
                    )}

                    {group.type === "off-chain" && (
                        <Box mb="30px">
                            {!group.credentials && (
                                <>
                                    <Text mb="10px" color="balticSea.800">
                                        Share invite code
                                    </Text>

                                    <InputGroup size="lg">
                                        <Input
                                            pr="50px"
                                            placeholder="Invite code"
                                            value={inviteCode}
                                            isDisabled
                                        />
                                        <InputRightElement mr="5px">
                                            <Tooltip
                                                label={
                                                    hasCopiedInviteCode
                                                        ? "Copied!"
                                                        : "Copy"
                                                }
                                                closeOnClick={false}
                                                hasArrow
                                            >
                                                <IconButton
                                                    variant="link"
                                                    aria-label="Copy invite link"
                                                    onClick={onCopyInviteCode}
                                                    onMouseDown={(e) =>
                                                        e.preventDefault()
                                                    }
                                                    icon={
                                                        <Icon
                                                            color="sunsetOrange.600"
                                                            boxSize="5"
                                                            as={FiCopy}
                                                        />
                                                    }
                                                />
                                            </Tooltip>
                                        </InputRightElement>
                                    </InputGroup>
                                </>
                            )}

                            <Text mb="10px" color="balticSea.800">
                                {!group.credentials
                                    ? "Share invite link"
                                    : "Share access link"}
                            </Text>

                            <InputGroup size="lg">
                                <Input
                                    pr="50px"
                                    placeholder={
                                        !group.credentials
                                            ? "Invite link"
                                            : "Access link"
                                    }
                                    value={_clientLink}
                                    isDisabled
                                />
                                <InputRightElement mr="5px">
                                    <Tooltip
                                        label={hasCopied ? "Copied!" : "Copy"}
                                        closeOnClick={false}
                                        hasArrow
                                    >
                                        <IconButton
                                            variant="link"
                                            aria-label="Copy invite link"
                                            onClick={onCopy}
                                            onMouseDown={(e) =>
                                                e.preventDefault()
                                            }
                                            icon={
                                                <Icon
                                                    color="sunsetOrange.600"
                                                    boxSize="5"
                                                    as={FiCopy}
                                                />
                                            }
                                        />
                                    </Tooltip>
                                </InputRightElement>
                            </InputGroup>

                            {!group.credentials && (
                                <Button
                                    mt="10px"
                                    variant="link"
                                    color="balticSea.600"
                                    textDecoration="underline"
                                    onClick={generateInviteLink}
                                >
                                    Generate new link
                                </Button>
                            )}
                        </Box>
                    )}

                    <Button
                        width="100%"
                        variant="solid"
                        colorScheme="tertiary"
                        onClick={() => onClose()}
                    >
                        Close
                    </Button>
                </ModalBody>
            </ModalContent>
        </Modal>
    )
}

This should be the final result:

Screenshot 2025-01-13 at 8 56 43 PM

Please let me know if you have any questions.

@pheobeayo
Copy link
Contributor Author

@vplasencia , thank you!, I will work on the update.

…code): updated the PR

updated the add-member-modal tsx file on updating the copy link button to copy the invited code
@pheobeayo
Copy link
Contributor Author

Hey @vplasencia , How do I fix the test code issues, I have implemented the invite code link in the appropriate place as requested, however where debugging the test codes, I didn't see the issue from my PR but how can this be fixed? any help you can render regarding this?

@vplasencia
Copy link
Member

Hey @pheobeayo the CI issue is gone now. I just had to re-run the tests in the CI.

@pheobeayo
Copy link
Contributor Author

Hey @pheobeayo the CI issue is gone now. I just had to re-run the tests in the CI.

Thank you so much @vplasencia , Please can you kindly review this.

Copy link
Member

@vplasencia vplasencia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @pheobeayo! Thank you very much for the update. I just left one comment. When it's solved, the PR will be ready to be merged.

apps/dashboard/src/pages/group.tsx Outdated Show resolved Hide resolved
@pheobeayo
Copy link
Contributor Author

Hey @pheobeayo! Thank you very much for the update. I just left one comment. When it's solved, the PR will be ready to be merged.

I have fixed this. Kindly review this, @vplasencia. Once this is successfully merged, I would like to solve the other issue I was assigned to.

@pheobeayo pheobeayo requested a review from vplasencia January 18, 2025 09:36
Copy link
Member

@vplasencia vplasencia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Thank you very much @pheobeayo!

@vplasencia vplasencia changed the base branch from main to dev January 18, 2025 11:24
@vplasencia vplasencia merged commit 9018762 into bandada-infra:dev Jan 18, 2025
5 checks passed
Copy link

gitpoap-bot bot commented Jan 18, 2025

Congrats, your important contribution to this open-source project has earned you a GitPOAP!

GitPOAP: 2025 Bandada Contributor:

GitPOAP: 2025 Bandada Contributor GitPOAP Badge

Head to gitpoap.io & connect your GitHub account to mint!

Learn more about GitPOAPs here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a text box to show and copy the group invite code
2 participants