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

keyword search for quantifiers & Quantify multiple praise #499

Merged
merged 11 commits into from
Jun 30, 2022
47 changes: 47 additions & 0 deletions packages/api/src/praise/controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
PraiseDocument,
PraiseDto,
QuantificationCreateUpdateInput,
QuantifyMultiplePraiseInput,
} from './types';
import { praiseWithScore, getPraisePeriod } from './utils/core';

Expand Down Expand Up @@ -201,3 +202,49 @@ export const quantify = async (
const response = await praiseDocumentListTransformer(affectedPraises);
res.status(200).json(response);
};

export const quantifyMultiple = async (
Copy link
Collaborator

@mattyg mattyg Jun 26, 2022

Choose a reason for hiding this comment

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

This function will need to have same logic used in the quantify function to determine all the praises with an affected scoreRealized. It probably makes sense to pull that logic out into a utility function and use it in both controllers.

The reason for that logic is so the "Duplicate Score" display is updated when the original praise's score is updated. See the screencast below:

Kazam_screencast_00003.mp4

Copy link
Member

Choose a reason for hiding this comment

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

This function will need to have same logic used in the quantify function to determine all the praises with an affected scoreRealized. It probably makes sense to pull that logic out into a utility function and use it in both controllers.

The reason for that logic is so the "Duplicate Score" display is updated when the original praise's score is updated. See the screencast below:

Kazam_screencast_00003.mp4

☝️☝️ @nebs-dev, this remains to be done.

req: TypedRequestBody<QuantifyMultiplePraiseInput>,
res: TypedResponse<PraiseDto[]>
): Promise<void> => {
const { score, praiseIds } = req.body;

const affectedPraises = await Promise.all(
praiseIds.map(async (id) => {
const praise = await PraiseModel.findById(id).populate(
'giver receiver forwarder'
);

if (!praise) throw new NotFoundError('Praise');

const period = await getPraisePeriod(praise);

if (!period)
throw new BadRequestError('Praise does not have an associated period');

if (!res.locals.currentUser?._id) {
throw new InternalServerError('Current user not found.');
}

const quantification = praise.quantifications.find((q) =>
q.quantifier.equals(res.locals.currentUser._id)
);

if (!quantification)
throw new BadRequestError(
'User not assigned as quantifier for praise.'
);

quantification.score = score;
quantification.dismissed = false;
quantification.duplicatePraise = undefined;

await praise.save();

return praise;
})
);

const response = await praiseDocumentListTransformer(affectedPraises);
res.status(200).json(response);
};
5 changes: 5 additions & 0 deletions packages/api/src/praise/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,10 @@ praiseRouter.patchAsync(
authMiddleware(UserRole.QUANTIFIER),
controller.quantify
);
praiseRouter.patchAsync(
'/quantify',
authMiddleware(UserRole.QUANTIFIER),
controller.quantifyMultiple
);

export { praiseRouter };
5 changes: 5 additions & 0 deletions packages/api/src/praise/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ export interface QuantificationCreateUpdateInput {
duplicatePraise: string;
}

export interface QuantifyMultiplePraiseInput {
score: number;
praiseIds: string[];
}

export interface Receiver {
_id: string;
praiseCount: number;
Expand Down
8 changes: 5 additions & 3 deletions packages/frontend/src/components/form/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

interface SearchInputProps {
handleChange: (element) => void;
value: string;
value?: string;
placeholder?: string;
}

const SearchInput = ({
handleChange,
value,
placeholder = 'Search',
}: SearchInputProps): JSX.Element => {
return (
<div className="relative flex items-center border border-warm-gray-400 h-[42px]">
<div className="relative flex items-center border border-warm-gray-400">
<div className="absolute inset-y-0 left-0 flex items-center pl-3">
<span className="text-warm-gray-800 dark:text-white">
<FontAwesomeIcon
Expand All @@ -25,7 +27,7 @@ const SearchInput = ({
className="block pl-8 bg-transparent border-none outline-none focus:ring-0"
name="search"
type="text"
placeholder="Search"
placeholder={placeholder}
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

value={value}
onChange={(e: React.ChangeEvent<HTMLInputElement>): void =>
handleChange(e.target.value)
Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/src/model/periods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,9 @@ export const PeriodQuantifierReceiverPraise = selectorFamily({
const userId = get(ActiveUserId);
const listKey = periodQuantifierPraiseListKey(periodId);
const praiseList = get(AllPraiseList(listKey));

if (!praiseList) return undefined;

return praiseList.filter(
(praise) =>
praise &&
Expand Down
28 changes: 28 additions & 0 deletions packages/frontend/src/model/praise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ type useQuantifyPraiseReturn = {
duplicatePraise: string | null
) => Promise<void>;
};

/**
* Hook that returns a function to use for closing a period
*/
Expand Down Expand Up @@ -296,3 +297,30 @@ export const useQuantifyPraise = (): useQuantifyPraiseReturn => {
);
return { quantify };
};

type useQuantifyMultiplePraiseReturn = {
quantifyMultiple: (score: number, praiseIds: string[]) => Promise<void>;
};

export const useQuantifyMultiplePraise =
(): useQuantifyMultiplePraiseReturn => {
const apiAuthClient = makeApiAuthClient();

const quantifyMultiple = useRecoilCallback(
({ set }) =>
async (score: number, praiseIds: string[]): Promise<void> => {
const response: AxiosResponse<PraiseDto[]> =
await apiAuthClient.patch('/praise/quantify', {
score,
praiseIds,
});

const praises = response.data;

praises.forEach((praise) => {
set(SinglePraise(praise._id), praise);
});
}
);
return { quantifyMultiple };
};
4 changes: 2 additions & 2 deletions packages/frontend/src/pages/EventLogs/EventLogsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const EventLogsPage = (): JSX.Element => {
</div>

{/* Search */}
<div className="w-5/12 mt-5 mb-5 mr-4">
<div className="w-5/12 mt-5 mb-5 mr-4 h-[42px]">
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use tailwind's built-in sizing classes instead of fixed pixel sizes?

Copy link
Member

Choose a reason for hiding this comment

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

We just want to ensure all the inputs are the same height. If that can be achieved without specifying a fixed height, all the better.

<SearchInput
handleChange={(e): void => {
setSearchValue(e);
Expand All @@ -120,7 +120,7 @@ const EventLogsPage = (): JSX.Element => {
</div>

{/* Sort */}
<div className="w-2/12 mt-5 mb-5 ml-auto mr-5">
<div className="w-2/12 mt-5 mb-5 ml-auto mr-5 h-[42px]">
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

<SelectInput
handleChange={(e): void => {
setSelectedSort(e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPrayingHands } from '@fortawesome/free-solid-svg-icons';

interface Props {
disabled?: boolean;
onClick();
}

const QuantifyMultipleButton = ({
disabled = false,
onClick,
}: Props): JSX.Element => {
return (
<button
disabled={disabled}
className={
disabled
? 'praise-button-disabled space-x-2'
: 'praise-button space-x-2'
}
onClick={onClick}
>
<FontAwesomeIcon icon={faPrayingHands} size="1x" />
Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you think about using the "unbalanced scale" icon instead of praying hands? https://fontawesome.com/search?q=scale%20unbalanced&s=solid%2Cbrands%2Cregular

<span>Quantify</span>
</button>
);
};

export default QuantifyMultipleButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import ScrollableDialog from '@/components/ScrollableDialog';
import QuantifyMultipleButton from '@/pages/QuantifyPeriodReceiver/components/QuantifyMultipleButton';
import QuantifySlider from '@/pages/QuantifyPeriodReceiver/components/QuantifySlider';
import { faCalculator, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { PraiseDto } from 'api/dist/praise/types';
import { useState } from 'react';

interface QuantifyMultipleDialogProps {
open: boolean;
onClose(): void;
selectedPraises: PraiseDto[];
allowedValues: number[];
onSetScore(newScore: number, selectedPraises: PraiseDto[]);
}

const QuantifyMultipleDialog = ({
open = false,
onClose,
selectedPraises,
allowedValues,
onSetScore,
}: QuantifyMultipleDialogProps): JSX.Element | null => {
const [score, setScore] = useState<number>(0);

return (
<ScrollableDialog open={open} onClose={onClose}>
<div className="w-full h-full">
<div className="flex justify-end p-6">
<button className="praise-button-round" onClick={onClose}>
<FontAwesomeIcon icon={faTimes} size="1x" />
</button>
</div>
<div className="px-20 space-y-6">
<div className="flex justify-center">
<FontAwesomeIcon icon={faCalculator} size="2x" />
</div>
<h2 className="text-center">
Quantify selected ({selectedPraises.length}) praises
mattyg marked this conversation as resolved.
Show resolved Hide resolved
</h2>

<div className="text-center">
<QuantifySlider
allowedScores={allowedValues}
onChange={(newScore): void => setScore(newScore)}
/>
</div>

<div className="flex justify-center">
<QuantifyMultipleButton
onClick={(): void => {
onSetScore(score, selectedPraises);
onClose();
}}
/>
</div>
</div>
</div>
</ScrollableDialog>
);
};

export default QuantifyMultipleDialog;
Loading