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

Add scores on request page #1957

Merged
merged 2 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 140 additions & 10 deletions web/components/templates/requestsV2/requestRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from "@heroicons/react/24/solid";
import {
addRequestLabel,
addRequestScore,
updateRequestFeedback,
} from "../../../services/lib/requests";
import useNotification from "../../shared/notification/useNotification";
Expand Down Expand Up @@ -57,13 +58,17 @@ const RequestRow = (props: {
const org = useOrg();

const [isAddingLabel, setIsAddingLabel] = useState(false);
const [isScoresAddingLabel, setIsScoresAddingLabel] = useState(false);
const [isScoresAdding, setIsScoresAdding] = useState(false);
const [isAdding, setIsAdding] = useState(false);
const [currentProperties, setCurrentProperties] = useState<
{
[key: string]: string;
}[]
>();

const [currentScores, setCurrentScores] = useState<Record<string, number>>();

const router = useRouter();
const { setNotification } = useNotification();

Expand All @@ -85,7 +90,9 @@ const RequestRow = (props: {
});

setCurrentProperties(currentProperties);
}, [properties, request.customProperties]);
const currentScores: Record<string, number> = request.scores || {};
setCurrentScores(currentScores);
}, [properties, request.customProperties, request.scores]);

const updateFeedbackHandler = async (requestId: string, rating: boolean) => {
updateRequestFeedback(requestId, rating)
Expand Down Expand Up @@ -151,6 +158,57 @@ const RequestRow = (props: {
}
};

const onAddScoreHandler = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsScoresAdding(true);

const formData = new FormData(e.currentTarget);
const key = formData.get("key") as string;
const value = formData.get("value") as any as number;

if (currentScores && currentScores[key]) {
setNotification("Score already exists", "error");
setIsScoresAdding(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: in the future, to avoid having to set states everything for loading, use useMutation

https://tanstack.com/query/v4/docs/framework/react/reference/useMutation

return;
}

if (!key || !value || org?.currentOrg?.id === undefined) {
setNotification("Error adding score", "error");
setIsScoresAdding(false);
return;
}
try {
const res = await addRequestScore(
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: Can a request have more than 1 score? If im understanding right, the addRequestScore function adds a score to an array of scores?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@ScottMktn Yes, request can have multiple scores but user can add scores 1 by 1 like custom properties

request.id,
org?.currentOrg?.id,
key,
value
);

if (res?.status === 201) {
setNotification("Score added", "success");
setCurrentScores(
currentScores
? {
...currentScores,
[key]: value,
}
: { [key]: value }
);

setIsScoresAdding(false);
} else {
setNotification("Error adding score", "error");
setIsScoresAdding(false);
}
} catch (err) {
console.error(err);
setNotification(`Error adding score: ${err}`, "error");
setIsScoresAdding(false);
return;
}
};

return (
<div className="flex flex-col h-full space-y-8">
<div className="flex flex-row items-center">
Expand Down Expand Up @@ -358,13 +416,85 @@ const RequestRow = (props: {
})}
</div>
</div>
{request.scores && (
<div className="flex flex-col">
<div className="font-semibold text-gray-900 dark:text-gray-100 text-sm items-center flex">
Scores{" "}
</div>
<div className="flex flex-wrap gap-4 text-sm items-center pt-2">
{Object.entries(request?.scores).map(([key, value]) => (

<div className="flex flex-col">
<div className="font-semibold text-gray-900 dark:text-gray-100 text-sm items-center flex">
Scores{" "}
<Tooltip title="Add a new score" placement="top">
<button
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Use HcButton

onClick={() => {
setIsScoresAddingLabel(!isScoresAddingLabel);
}}
className="ml-1.5 p-0.5 shadow-sm bg-white dark:bg-black border border-gray-300 dark:border-gray-700 rounded-md h-fit"
>
{isScoresAddingLabel ? (
<MinusIcon className="h-3 w-3 text-gray-500" />
) : (
<PlusIcon className="h-3 w-3 text-gray-500" />
)}
</button>
</Tooltip>
</div>
{isScoresAddingLabel && (
<form
onSubmit={onAddScoreHandler}
className="flex flex-row items-end space-x-2 py-4 mb-4 border-b border-gray-300 dark:border-gray-700"
>
<div className="flex flex-col space-y-1">
<label
htmlFor="key"
className="block text-sm font-semibold leading-6 text-gray-900 dark:text-gray-100"
>
Key
</label>
<div className="">
<input
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Use TextInput

type="text"
name="key"
id="key"
required
className={clsx(
"bg-white dark:bg-black block w-full rounded-md px-2 py-1 text-sm text-gray-900 dark:text-gray-100 shadow-sm placeholder:text-gray-400 border border-gray-300 dark:border-gray-700 sm:leading-6"
)}
placeholder={"Key"}
/>
</div>
</div>
<div className="flex flex-col space-y-1">
<label
htmlFor="value"
className="block text-sm font-semibold leading-6 text-gray-900 dark:text-gray-100"
>
Value
</label>
<div className="">
<input
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: see above

type="number"
name="value"
id="value"
required
className={clsx(
"bg-white dark:bg-black block w-full rounded-md px-2 py-1 text-sm text-gray-900 dark:text-gray-100 shadow-sm placeholder:text-gray-400 border border-gray-300 dark:border-gray-700 sm:leading-6"
)}
placeholder={"Value"}
/>
</div>
</div>
<button
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Use HcButton component

type="submit"
className="h-fit flex flex-row rounded-md bg-black dark:bg-white px-4 py-2 text-xs font-semibold border border-black dark:border-white hover:bg-gray-900 dark:hover:bg-gray-100 text-gray-50 dark:text-gray-900 shadow-sm hover:text-gray-300 dark:hover:text-gray-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500"
>
{isAdding && (
<ArrowPathIcon className="w-4 h-4 mr-1.5 animate-spin" />
)}
Add
</button>
</form>
)}

<div className="flex flex-wrap gap-4 text-sm items-center pt-2">
{currentScores &&
Object.entries(currentScores).map(([key, value]) => (
<li
className="flex flex-col space-y-1 justify-between text-left p-2.5 shadow-sm border border-gray-300 dark:border-gray-700 rounded-lg min-w-[5rem]"
key={key}
Expand All @@ -375,9 +505,9 @@ const RequestRow = (props: {
<p className="text-gray-700 dark:text-gray-300">{value}</p>
</li>
))}
</div>
</div>
)}
</div>

{displayPreview && (
<div className="flex flex-col space-y-8">
<div className="flex w-full justify-end">
Expand Down
23 changes: 23 additions & 0 deletions web/services/lib/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,26 @@ export const addRequestLabel = async (
})
).response;
};

export const addRequestScore = async (
requestId: string,
orgId: string,
key: string,
value: number
) => {
const jawn = getJawnClient(orgId);
return (
await jawn.POST("/v1/request/{requestId}/score", {
body: {
scores: {
[key]: value,
},
},
params: {
path: {
requestId,
},
},
})
).response;
};
Loading