Skip to content

Commit

Permalink
Enhance connection modal features (#100)
Browse files Browse the repository at this point in the history
* Add loading symbol to connection

* REmove console.log

* Cleaned up and updated the startup modal to make it cleaner

* Made lots of changes to modal to improving styling + errors handling + UX flow

* Reoganize packages
  • Loading branch information
iyasinn authored Sep 5, 2024
1 parent 78ec496 commit 7963318
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 48 deletions.
158 changes: 110 additions & 48 deletions components/startups/StartupProfileTile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useState, Fragment } from "react";
import { useState, Fragment, useCallback } from "react";
import { Dialog, Transition } from "@headlessui/react";
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/solid";
import { FaSlack, FaEnvelope } from "react-icons/fa";
import useSupabase from "../../hooks/useSupabase";
import supabase from "../../utils/supabaseClient";
import { StartupProfile, StartupProfileMetadata } from "../../utils/types";
Expand All @@ -25,12 +27,16 @@ export default function StartupProfileTile({
} = startupProfile;

const displayName = profileName ?? profileUsername;

const slackLink =
(profileSlackLink as string) ??
"https://app.slack.com/client/T04JWPLEL5B/C04KPD6KS80";
const { role, headshot_src: headshotSrc } = startupProfileMetadata;
const [connectDialogOpen, setConnectDialogOpen] = useState<boolean>(false);
const [connectionSent, setConnectionSent] = useState<boolean>(false);
const [connectionStatus, setConnectionStatus] = useState<{
success: boolean;
message: string;
} | null>(null);
const [connectionMessage, setConnectionMessage] = useState<string>("");

const { rank } = useSupabase();
Expand All @@ -40,14 +46,14 @@ export default function StartupProfileTile({
const anonymousPersonImage =
"https://www.shutterstock.com/image-vector/default-avatar-profile-icon-social-600nw-1677509740.jpg";

function sendConnectionMessage() {
const [isLoading, setIsLoading] = useState<boolean>(false);

const sendConnectionMessage = useCallback(() => {
const session = supabase.auth.session();
// Null handling.
if (!session) {
return;
}
if (!session) return;
const { access_token: accessToken } = session;

setIsLoading(true);
const body = JSON.stringify({
recipient: profileEmail,
message: connectionMessage,
Expand All @@ -59,13 +65,30 @@ export default function StartupProfileTile({
Authorization: `Bearer ${accessToken}`,
},
body,
}).then((response) => {
if (response.ok) {
})
.then(async (response) => {
setConnectDialogOpen(false);
setConnectionSent(true);
}
});
}
setIsLoading(false);

if (response.ok) {
setConnectionStatus({
success: true,
message: "Connection sent successfully!",
});
} else {
const errorBody = await response.text();
setConnectionStatus({ success: false, message: errorBody });
}
})
.catch((error) => {
console.log("Error sending connection request:", error);
setIsLoading(false);
setConnectionStatus({
success: false,
message: "An error occurred while sending the connection request.",
});
});
}, [profileEmail, connectionMessage]);

return (
<div className="flex flex-col items-center p-2">
Expand All @@ -81,10 +104,21 @@ export default function StartupProfileTile({

<h1 className="mt-1 text-sm">{displayName}</h1>
<p className="text-gray-500 text-xs">{role}</p>
{connectionSent ? (
<p className="text-xs px-2 py-1 mt-2 font-inter text-center">
connection sent successfully!
</p>
{connectionStatus ? (
<div
className={`flex items-start text-xs mt-2 p-1 font-inter w-32 ${
connectionStatus.success
? "text-green-600 bg-green-100"
: "text-red-600 bg-red-100"
} rounded-md`}
>
{connectionStatus.success ? (
<CheckCircleIcon className="w-4 h-4 mr-1 flex-shrink-0" />
) : (
<XCircleIcon className="w-4 h-4 mr-1 flex-shrink-0" />
)}
<p className="break-words">{connectionStatus.message}</p>
</div>
) : (
<button
type="button"
Expand Down Expand Up @@ -128,47 +162,75 @@ export default function StartupProfileTile({
leaveTo="opacity-0"
>
<Dialog.Panel className="w-full max-w-lg transform overflow-hidden rounded-2xl bg-white px-6 py-2 text-left align-middle shadow-xl transition-all">
{v1Community ? (
<div className="flex flex-col justify-between items-center">
<p className="text-sm text-gray-400 p-4">
<div className="flex flex-col justify-between items-start">
{(v1Community || v1Member) && (
<p className="text-sm p-4 flex items-center">
<FaSlack className="mr-2 w-4 h-4" />
<a
href={slackLink}
target="_blank"
rel="noreferrer"
className="hover:underline text-blue-600"
>{`Message ${displayName} on Slack`}</a>
</p>
{v1Member ? (
<>
<input
value={connectionMessage}
onChange={(evt) =>
setConnectionMessage(evt.target.value)
}
className="w-full text-sm border border-gray-400 border-1 rounded h-fit"
type="text"
placeholder={`Send a message by email to ${displayName}...`}
/>
<button
className="text-sm text-gray-400 p-4"
type="button"
onClick={sendConnectionMessage}
>
Send
</button>
</>
) : (
)}

{v1Member && (
<div className="w-full px-4 pb-4">
<div className="flex items-center mb-2">
<FaEnvelope className="mr-2 w-4 h-4" />
<span className="text-sm">Send an email message</span>
</div>
<div className="flex w-full">
<div className="flex-grow relative">
<textarea
value={connectionMessage}
onChange={(evt) =>
setConnectionMessage(evt.target.value)
}
className="w-full text-sm border border-gray-400 border-1 rounded-l p-2 resize-none min-h-[40px] max-h-[200px] overflow-hidden"
placeholder={`Send a message by email to ${displayName}...`}
rows={1}
onInput={(e) => {
const target = e.target as HTMLTextAreaElement;
target.style.height = "auto";
target.style.height = `${target.scrollHeight}px`;
}}
/>
</div>
<div className="flex items-start">
<button
className="text-sm ml-1 text-white bg-blue-600 hover:bg-blue-700 px-2 rounded flex items-center justify-center h-[40px]"
type="button"
onClick={sendConnectionMessage}
disabled={isLoading}
>
{isLoading ? (
"Sending..."
) : (
<>
<span className="text-xs mr-1"></span> Send
</>
)}
</button>
</div>
</div>
</div>
)}

{/* {!(v1Community || v1Member) && (
<p className="text-sm text-gray-400">
Become a V1 Member to connect with {displayName}{" "}
through email!
</p>
)}
</div>
) : (
<p className="text-sm text-gray-400">
Finish signing in to connect with {displayName} through
Slack!
</p>
)}
)} */}

{!(v1Community || v1Member) && (
<p className="text-sm text-gray-400">
Finish signing in to connect with members of V1!
</p>
)}
</div>
</Dialog.Panel>
</Transition.Child>
</div>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"react-fast-marquee": "^1.3.1",
"react-ga4": "^1.4.1",
"react-html-parser": "^2.0.2",
"react-icons": "^5.3.0",
"react-pdf": "^5.7.1",
"react-reveal": "^1.2.2",
"react-scroll-parallax": "^3.0.5",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4059,6 +4059,11 @@ react-html-parser@^2.0.2:
dependencies:
htmlparser2 "^3.9.0"

react-icons@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.3.0.tgz#ccad07a30aebd40a89f8cfa7d82e466019203f1c"
integrity sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==

react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
Expand Down

0 comments on commit 7963318

Please sign in to comment.