Skip to content

Commit

Permalink
Merge pull request #285 from bettersg/feat/custom-replies
Browse files Browse the repository at this point in the history
Feat/custom replies
  • Loading branch information
sarge1989 committed May 1, 2024
2 parents cac1d8e + eee6517 commit 6144ac8
Show file tree
Hide file tree
Showing 33 changed files with 646 additions and 138 deletions.
38 changes: 18 additions & 20 deletions checkers-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const router = createBrowserRouter([
]);

function App() {
const { setCheckerId, setCheckerName, setAuthScopes } = useUser();
const { setCheckerDetails, setAuthScopes } = useUser();
const [isLoading, setIsLoading] = useState(true);
//for global states: userID, name and messages

Expand Down Expand Up @@ -74,16 +74,16 @@ function App() {
}
if (data.isNewUser || data.isOnboardingComplete === false) {
// TODO BRENNAN: Redirect to onboarding page
signInWithToken(
data.customToken,
setCheckerId,
setCheckerName,
data.checkerId,
data.name
)
signInWithToken(data.customToken)
.then(() => {
// Handle post-signIn success actions here, if any
console.log("Sign-in successful");
setCheckerDetails((currentChecker) => ({
...currentChecker,
checkerId: data.checkerId,
checkerName: data.name,
isAdmin: data.isAdmin,
tier: data.tier,
}));
setAuthScopes(data);
router.navigate("/onboarding");
})
Expand All @@ -97,16 +97,15 @@ function App() {
setAuthScopes(data);
} else {
//if existing user
signInWithToken(
data.customToken,
setCheckerId,
setCheckerName,
data.checkerId,
data.name
)
signInWithToken(data.customToken)
.then(() => {
// Handle post-signIn success actions here, if any
console.log("Sign-in successful");
setCheckerDetails((currentChecker) => ({
...currentChecker,
checkerId: data.checkerId,
checkerName: data.name,
isAdmin: data.isAdmin,
tier: data.tier,
}));
})
.catch((err) => {
console.error(
Expand All @@ -121,12 +120,11 @@ function App() {
console.error("Error fetching custom token:", err);
})
.finally(() => {
console.log("Sign-in complete");
setIsLoading(false);
});
}
}
}, [setCheckerId, setCheckerName]);
}, [setCheckerDetails]);

if (isLoading) {
return <Loading />;
Expand Down
6 changes: 3 additions & 3 deletions checkers-app/src/components/common/BotNavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {

export default function NavbarDefault() {
const navigate = useNavigate();
const { pendingCount } = useUser();
const { checkerDetails } = useUser();
// Helper function to decide if the badge is invisible
const isBadgeInvisible = pendingCount === 0;
const isBadgeInvisible = checkerDetails.pendingCount === 0;

return (
<Navbar className="fixed bottom-0 left-0 z-50 w-full h-16 bg-primary-color2 dark:bg-dark-highlight-color border-0">
Expand All @@ -34,7 +34,7 @@ export default function NavbarDefault() {
<Badge
invisible={isBadgeInvisible}
color="teal"
content={pendingCount}
content={checkerDetails.pendingCount}
placement="top-end"
>
<CheckBadgeIcon className="h-7 w-7 text-white" />
Expand Down
19 changes: 11 additions & 8 deletions checkers-app/src/components/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Loading from "../common/Loading";

export default function Dashboard() {
const [isLoading, setIsLoading] = useState(false);
const { checkerId, pendingCount, setPendingCount } = useUser();
const { checkerDetails, setCheckerDetails } = useUser();
const [totalVotes, setTotalVotes] = useState<number>(0);
const [accuracyRate, setAccuracyRate] = useState<number | null>(0);
const [avgResponseTime, setAvgResponseTime] = useState<number>(0);
Expand All @@ -19,32 +19,35 @@ export default function Dashboard() {
useEffect(() => {
const fetchChecker = async () => {
setIsLoading(true);
if (!checkerId) {
if (!checkerDetails.checkerId) {
return;
}
const checker: Checker = await getChecker(checkerId);
const checker: Checker = await getChecker(checkerDetails.checkerId);
if (checker) {
setTotalVotes(checker.last30days.totalVoted);
setAccuracyRate(checker.last30days.accuracyRate);
setAvgResponseTime(checker.last30days.averageResponseTime);
setPeopleHelped(checker.last30days.peopleHelped);
setPendingCount(checker.pendingVoteCount);
//setPendingCount(checker.pendingVoteCount);
setIsLoading(false);
}
};
if (checkerId) {
if (checkerDetails.checkerId) {
fetchChecker();
}
}, [checkerId]);
}, [checkerDetails.checkerId]);

if (isLoading) {
return <Loading />;
}

return (
<div className="flex flex-col gap-y-4 left-right-padding">
{pendingCount > 0 && (
<PendingMessageAlert hasPending={true} pendingCount={pendingCount} />
{checkerDetails.pendingCount > 0 && (
<PendingMessageAlert
hasPending={true}
pendingCount={checkerDetails.pendingCount}
/>
)}
{/* {reviewCount > 0 && (
<PendingMessageAlert hasPending={false} pendingCount={pendingCount} />
Expand Down
10 changes: 5 additions & 5 deletions checkers-app/src/components/myvotes/MessagesDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { VoteSummary, VoteSummaryApiResponse } from "../../types";
import Pagination from "./Pagination"; // Make sure to create this component

const MessagesDisplay: FC = () => {
const { checkerId } = useUser();
const { checkerDetails } = useUser();
const [isLoading, setIsLoading] = useState(false);
const [votes, setVotes] = useState<VoteSummary[]>([]);
const [lastPath, setLastPath] = useState<string | null>(null);
Expand All @@ -39,11 +39,11 @@ const MessagesDisplay: FC = () => {
const fetchMessages = async () => {
setIsLoading(true);
try {
if (!checkerId) {
if (!checkerDetails.checkerId) {
throw new Error("Checker Id missing.");
}
const response: VoteSummaryApiResponse = await getCheckerVotes(
checkerId,
checkerDetails.checkerId,
activeTab.toLowerCase(),
5,
lastPath
Expand All @@ -60,10 +60,10 @@ const MessagesDisplay: FC = () => {
setIsLoading(false);
}
};
if (checkerId) {
if (checkerDetails.checkerId) {
fetchMessages();
}
}, [checkerId, activeTab, currentPage]);
}, [checkerDetails.checkerId, activeTab, currentPage]);

const handleTabChange = (tab: "pending" | "voted") => {
setActiveTab(tab);
Expand Down
121 changes: 121 additions & 0 deletions checkers-app/src/components/vote/CustomReply.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useState, useEffect } from "react";
import { Alert } from "@material-tailwind/react";
import { useNavigate } from "react-router-dom";
import {
getMessage,
postCustomReply,
sendWhatsappTestMessage,
} from "../../services/api";
import { useUser } from "../../providers/UserContext";

interface PropType {
messageId: string | undefined;
}

export default function CustomReply(Prop: PropType) {
//load props
const navigate = useNavigate();
const { messageId } = Prop;
const { checkerDetails } = useUser();
const [customReplyText, setCustomReplyText] = useState("");
const [showAlerts, setShowAlerts] = useState(false);

useEffect(() => {
const fetchMessage = async () => {
if (messageId) {
const message = await getMessage(messageId);
if (message.customReply) {
setCustomReplyText(message?.customReply?.text ?? "");
} else {
setCustomReplyText("");
}
}
};
if (messageId) {
fetchMessage();
}
}, []);

const handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setCustomReplyText(event.target.value);
};

const handleSubmit = () => {
// Implement what happens when the comment is posted (e.g., send to a server)
if (checkerDetails.checkerId && customReplyText && messageId) {
postCustomReply(
messageId,
checkerDetails.checkerId,
customReplyText
).then(() => {
console.log("Custom reply posted successfully");
navigate("/votes");
});
}
};

const handleWhatsappTest = () => {
if (checkerDetails.checkerId && customReplyText) {
sendWhatsappTestMessage(checkerDetails.checkerId, customReplyText)
.then((data) => {
console.log(data);
console.log("Test is successfull");
setShowAlerts(false);
})
.catch((error) => {
console.error(error);
setShowAlerts(true);
});
}
};

return (
<div className="relative w-full md:w-[32rem]">
<div className="relative w-full min-w-[200px]">
<textarea
rows={8}
value={customReplyText}
onChange={handleInputChange}
className="peer h-full min-h-[100px] w-full resize-none rounded-[7px] border border-blue-gray-200 border-t-transparent bg-transparent px-3 py-2.5 font-sans text-sm font-normal text-blue-gray-700 outline outline-0 transition-all placeholder-shown:border placeholder-shown:border-blue-gray-200 placeholder-shown:border-t-blue-gray-200 focus:border-2 focus:border-gray-900 focus:border-t-transparent focus:outline-0"
placeholder=" "
/>
<label className="before:content[' '] after:content[' '] pointer-events-none absolute left-0 -top-1.5 flex h-full w-full select-none text-[11px] font-normal leading-tight text-blue-gray-400 transition-all before:pointer-events-none before:mt-[6.5px] before:mr-1 before:box-border before:block before:h-1.5 before:w-2.5 before:rounded-tl-md before:border-t before:border-l before:border-blue-gray-200 before:transition-all after:pointer-events-none after:mt-[6.5px] after:ml-1 after:box-border after:block after:h-1.5 after:w-2.5 after:flex-grow after:rounded-tr-md after:border-t after:border-r after:border-blue-gray-200 after:transition-all peer-placeholder-shown:text-sm peer-placeholder-shown:leading-[3.75] peer-placeholder-shown:text-blue-gray-500 peer-placeholder-shown:before:border-transparent peer-placeholder-shown:after:border-transparent peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-gray-900 peer-focus:before:border-t-2 peer-focus:before:border-l-2 peer-focus:before:!border-gray-900 peer-focus:after:border-t-2 peer-focus:after:border-r-2 peer-focus:after:!border-gray-900">
Custom Reply
</label>
</div>
<div className="flex w-full justify-between py-1.5">
<button
className="relative h-8 max-h-[32px] w-8 max-w-[32px] select-none rounded-lg text-center align-middle font-sans text-xs font-medium uppercase text-blue-gray-500 transition-all hover:bg-blue-gray-500/10 active:bg-blue-gray-500/30"
type="button"
>
{/* SVG here */}
</button>
<div className="flex gap-2">
<button
onClick={handleWhatsappTest}
className="px-4 py-2 font-sans text-xs font-bold text-center text-gray-900 uppercase align-middle transition-all rounded-md select-none hover:bg-gray-900/10 active:bg-gray-900/20"
type="button"
>
Test on WhatsApp
</button>
<button
onClick={handleSubmit}
className="select-none rounded-md bg-gray-900 py-2 px-4 text-center align-middle font-sans text-xs font-bold uppercase text-white shadow-md shadow-gray-900/10 transition-all hover:shadow-lg hover:shadow-gray-900/20 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none"
type="button"
>
Submit Custom Reply
</button>
</div>
{showAlerts && (
<Alert
color="amber"
open={showAlerts}
onClose={() => setShowAlerts(false)}
>
A dismissible alert for showing message.
</Alert>
)}
</div>
</div>
);
}
13 changes: 9 additions & 4 deletions checkers-app/src/components/vote/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import VoteCategories from "./VoteCategories";
import MessageCard from "./MessageCard";
import { Typography } from "@material-tailwind/react";
import { Typography, Alert } from "@material-tailwind/react";
import { BackButton } from "../common/BackButton";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
Expand All @@ -11,9 +11,10 @@ import { getVote } from "../../services/api";
import CategoryRationalisation from "./Rationalisation";
import VoteResult from "./VoteResult";
import VotingChart from "./VotingChart";
import CustomReply from "./CustomReply";

export default function VotePage() {
const { checkerId } = useUser();
const { checkerDetails } = useUser();
const { messageId, voteRequestId } = useParams();
const [isLoading, setIsLoading] = useState(false);
const [vote, setVote] = useState<Vote | null>(null);
Expand All @@ -28,10 +29,10 @@ export default function VotePage() {
setIsLoading(false);
};

if (messageId && voteRequestId && checkerId) {
if (messageId && voteRequestId && checkerDetails.checkerId) {
fetchVote();
}
}, [checkerId]);
}, [checkerDetails.checkerId]);

if (isLoading) {
return <Loading />;
Expand All @@ -58,6 +59,7 @@ export default function VotePage() {
imageUrl={vote.signedImageUrl}
caption={vote.caption}
/>
<Alert variant="ghost">Sender: {vote.sender}</Alert>
{vote.category === null || !vote.isAssessed ? (
<>
<Typography
Expand Down Expand Up @@ -107,6 +109,9 @@ export default function VotePage() {
/>
</>
)}
{checkerDetails.tier === "expert" && (
<CustomReply messageId={messageId} />
)}
</div>
</>
);
Expand Down
Loading

0 comments on commit 6144ac8

Please sign in to comment.