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

Dework integration #1

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion api/hasura/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
'X-Hasura-User-Id': tokenRow.tokenable_id.toString(),
'X-Hasura-Role': profile.admin_view ? 'superadmin' : 'user',
});
} catch (e) {
} catch (e: any) {
res.status(401).json({
error: '401',
message: (e.message as string) || 'Unexpected error',
Expand Down
2 changes: 1 addition & 1 deletion scripts/setup-hardhat.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -e

FIND_DEV_PID="lsof -t -i:8545 -sTCP:LISTEN"

git submodule update --init --recursive
# git submodule update --init --recursive
yarn hardhat:install --frozen-lockfile
yarn hardhat:compile

Expand Down
9 changes: 8 additions & 1 deletion src/components/ProfileCard/ProfileCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import {
} from 'components';
import { USER_ROLE_ADMIN, USER_ROLE_COORDINAPE } from 'config/constants';
import { useNavigation } from 'hooks';
import { useProfileTasks } from 'recoilState';
import { useSetEditProfileOpen } from 'recoilState/ui';
import { EXTERNAL_URL_FEEDBACK } from 'routes/paths';

import { CardInfoText } from './CardInfoText';
import { GiftInput } from './GiftInput';
import { TasksSummary } from './TasksSummary';

import { IUser } from 'types';

Expand All @@ -28,7 +30,7 @@ const useStyles = makeStyles(theme => ({
alignItems: 'center',
justifyContent: 'space-between',
width: 330,
height: 452,
minHeight: 452,
margin: theme.spacing(1),
padding: theme.spacing(1.3, 1.3, 2),
background: theme.colors.background,
Expand Down Expand Up @@ -91,6 +93,7 @@ const useStyles = makeStyles(theme => ({
textAlign: 'center',
WebkitLineClamp: 4,
wordBreak: 'break-word',
width: '100%',
},
editButton: {
margin: theme.spacing(7, 0, 2),
Expand Down Expand Up @@ -133,6 +136,8 @@ export const ProfileCard = ({
const { getToMap, getToProfile } = useNavigation();
const setEditProfileOpen = useSetEditProfileOpen();

const tasks = useProfileTasks(user.address);

const userBioTextLength = user?.bio?.length ?? 0;
const skillsLength = user?.profile?.skills?.length ?? 0;

Expand Down Expand Up @@ -201,6 +206,8 @@ export const ProfileCard = ({
) : (
<ReadMore isHidden={hideUserBio}>{user.bio}</ReadMore>
)}

{!!tasks && <TasksSummary tasks={tasks} />}
</div>

{!disabled && updateGift && (
Expand Down
69 changes: 69 additions & 0 deletions src/components/ProfileCard/TasksSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { FC } from 'react';

import { makeStyles, Typography } from '@material-ui/core';

import { RightArrowIcon } from 'icons';

export interface Task {
id: string;
name: string;
permalink: string;
}

interface Props {
tasks: Task[];
}

const useStyles = makeStyles(theme => ({
root: {
textAlign: 'left',
margin: theme.spacing(1, 0),
padding: theme.spacing(1.5),
backgroundColor: theme.colors.white,
borderRadius: 8,
},
title: {
textTransform: 'uppercase',
color: theme.colors.lightText,
fontWeight: 600,
},
taskItem: {
display: 'flex',
alignItems: 'center',
color: theme.colors.mediumGray,
transition: 'color 200ms ease-out',
'&:hover': {
color: theme.colors.text,
},
},
taskName: {
flex: 1,
fontWeight: 600,
},
}));

export const TasksSummary: FC<Props> = ({ tasks }) => {
const classes = useStyles();
if (!tasks.length) return null;
return (
<div className={classes.root}>
<Typography variant="body2" className={classes.title}>
Completed Tasks
</Typography>
{tasks.map(task => (
<a
key={task.id}
href={task.permalink}
target="_blank"
rel="noreferrer"
className={classes.taskItem}
>
<Typography variant="body2" className={classes.taskName}>
{task.name}
</Typography>
<RightArrowIcon size="md" />
</a>
))}
</div>
);
};
8 changes: 8 additions & 0 deletions src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ export const API_URL = getEnvValue(
'REACT_APP_API_BASE_URL',
'https://missing-laravel-url.edu'
);
export const DEWORK_API_URL = getEnvValue(
'REACT_APP_DEWORK_API_URL',
'https://api.dework.xyz'
);
export const DEWORK_APP_INSTALL_URL = getEnvValue(
'REACT_APP_DEWORK_APP_INSTALL_URL',
'https://dework.xyz/apps/install/coordinape'
);
// The test key always returns: 10000000-aaaa-bbbb-cccc-000000000001
export const CAPTCHA_SITE_KEY = IN_PRODUCTION
? getEnvValue('REACT_APP_H_CAPTCHA', 'missing-captcha-site-key')
Expand Down
20 changes: 20 additions & 0 deletions src/icons/DeworkIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';

import { SvgIcon } from '@material-ui/core';

export const DeworkIcon = (props: any) => (
<SvgIcon {...props} viewBox="0 0 456 466">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M54.2447 69.3731L54.3512 69.2153C55.6535 67.292 56.9601 65.5509 58.2912 64C60.9333 60.9217 63.6717 58.5927 66.6634 57.0759C69.3628 55.7073 72.2682 55 75.495 55H222.999V0H157.997C156.631 0 155.22 0.0342585 153.77 0.102357C134.881 0.263072 120.191 0.158848 108.378 0.0750351C84.0321 -0.0976988 71.9061 -0.183733 60.4239 2.31489C42.5557 6.63759 26.7545 17.0566 15.7423 31.777C4.73008 46.4973 -0.803719 64.5973 0.0943794 82.959C0.992378 101.321 8.26598 118.794 20.6621 132.37L20.7389 132.3L114.394 232.732L20 333.957L20.1985 334.142C8.08471 347.644 0.981125 364.909 0.0943794 383.041C-0.803719 401.403 4.73008 419.503 15.7423 434.223C26.7545 448.943 42.5557 459.362 60.4239 463.685C71.9051 466.183 84.0299 466.098 108.372 465.925C120.188 465.841 134.882 465.737 153.78 465.898C155.226 465.966 156.634 466 157.997 466H222.999V411H75.495C68.0146 411 62.261 407.199 56.7992 400.171C55.6912 398.745 54.5953 397.186 53.4993 395.5L53.4982 395.508C53.4965 395.521 53.4948 395.534 53.493 395.547C53.4953 395.498 53.4976 395.449 53.5 395.4C53.7728 389.822 57.5112 374.841 61.2771 370.717L61.0863 370.543L72.7826 358H215C231.415 358 247.67 354.767 262.835 348.485C278.001 342.203 291.781 332.996 303.388 321.388C314.996 309.781 324.203 296.001 330.485 280.835C336.767 265.67 340 249.415 340 233C340 216.585 336.767 200.33 330.485 185.165C324.203 169.999 314.996 156.219 303.388 144.612C291.781 133.004 278.001 123.797 262.835 117.515C247.67 111.233 231.415 108 215 108H73.2816L60.4708 94.262C56.5144 89.1686 53.7515 75.7426 53.5 70.5996L53.493 70.4533L53.4993 70.5L53.5526 70.4182C53.7081 70.1795 53.8636 69.9434 54.0191 69.7098C54.0943 69.597 54.1695 69.4847 54.2447 69.3731ZM88.6407 446.915C80.2651 442.447 72.5047 436.98 66.4136 430.313C72.4324 436.626 80.1147 442.182 88.6407 446.915ZM88.6528 19.078C80.2681 23.5503 72.4992 29.0221 66.4036 35.6975C72.4268 29.3768 80.1172 23.8151 88.6528 19.078ZM223 55C246.375 55 269.522 59.6041 291.118 68.5494C312.714 77.495 332.336 90.606 348.865 107.135C365.394 123.664 378.505 143.286 387.451 164.882C396.396 186.478 401 209.625 401 233C401 256.375 396.396 279.522 387.451 301.118C378.505 322.714 365.394 342.336 348.865 358.865C332.336 375.394 312.714 388.505 291.118 397.451C269.522 406.396 246.375 411 223 411V466C253.598 466 283.896 459.973 312.165 448.264C340.434 436.555 366.12 419.392 387.756 397.756C409.392 376.12 426.555 350.434 438.264 322.165C449.973 293.896 456 263.598 456 233C456 202.402 449.973 172.104 438.264 143.835C426.555 115.566 409.392 89.88 387.756 68.2441C366.12 46.6081 340.434 29.4454 312.165 17.7361C283.896 6.0267 253.598 0 223 0V55ZM215 163C224.193 163 233.295 164.811 241.788 168.328C250.281 171.846 257.997 177.002 264.497 183.503C270.998 190.003 276.154 197.719 279.672 206.212C283.189 214.705 285 223.807 285 233C285 242.193 283.189 251.295 279.672 259.788C276.154 268.281 270.998 275.997 264.497 282.497C257.997 288.998 250.281 294.154 241.788 297.672C233.295 301.189 224.193 303 215 303H124.071L182.984 239.823C184.84 237.833 185.728 235.288 185.668 232.768C185.745 230.225 184.858 227.652 182.986 225.644L124.57 163H215Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M54.2447 69.3731L54.3512 69.2153C55.6535 67.292 56.9601 65.5509 58.2912 64C60.9333 60.9217 63.6717 58.5927 66.6634 57.0759C69.3628 55.7073 72.2682 55 75.495 55H222.999V0H157.997C156.631 0 155.22 0.0342585 153.77 0.102357C134.881 0.263072 120.191 0.158848 108.378 0.0750351C84.0321 -0.0976988 71.9061 -0.183733 60.4239 2.31489C42.5557 6.63759 26.7545 17.0566 15.7423 31.777C4.73008 46.4973 -0.803719 64.5973 0.0943794 82.959C0.992378 101.321 8.26598 118.794 20.6621 132.37L20.7389 132.3L114.394 232.732L20 333.957L20.1985 334.142C8.08471 347.644 0.981125 364.909 0.0943794 383.041C-0.803719 401.403 4.73008 419.503 15.7423 434.223C26.7545 448.943 42.5557 459.362 60.4239 463.685C71.9051 466.183 84.0299 466.098 108.372 465.925C120.188 465.841 134.882 465.737 153.78 465.898C155.226 465.966 156.634 466 157.997 466H222.999V411H75.495C68.0146 411 62.261 407.199 56.7992 400.171C55.6912 398.745 54.5953 397.186 53.4993 395.5L53.4982 395.508C53.4965 395.521 53.4948 395.534 53.493 395.547C53.4953 395.498 53.4976 395.449 53.5 395.4C53.7728 389.822 57.5112 374.841 61.2771 370.717L61.0863 370.543L72.7826 358H215C231.415 358 247.67 354.767 262.835 348.485C278.001 342.203 291.781 332.996 303.388 321.388C314.996 309.781 324.203 296.001 330.485 280.835C336.767 265.67 340 249.415 340 233C340 216.585 336.767 200.33 330.485 185.165C324.203 169.999 314.996 156.219 303.388 144.612C291.781 133.004 278.001 123.797 262.835 117.515C247.67 111.233 231.415 108 215 108H73.2816L60.4708 94.262C56.5144 89.1686 53.7515 75.7426 53.5 70.5996L53.493 70.4533L53.4993 70.5L53.5526 70.4182C53.7081 70.1795 53.8636 69.9434 54.0191 69.7098C54.0943 69.597 54.1695 69.4847 54.2447 69.3731ZM88.6407 446.915C80.2651 442.447 72.5047 436.98 66.4136 430.313C72.4324 436.626 80.1147 442.182 88.6407 446.915ZM88.6528 19.078C80.2681 23.5503 72.4992 29.0221 66.4036 35.6975C72.4268 29.3768 80.1172 23.8151 88.6528 19.078ZM223 55C246.375 55 269.522 59.6041 291.118 68.5494C312.714 77.495 332.336 90.606 348.865 107.135C365.394 123.664 378.505 143.286 387.451 164.882C396.396 186.478 401 209.625 401 233C401 256.375 396.396 279.522 387.451 301.118C378.505 322.714 365.394 342.336 348.865 358.865C332.336 375.394 312.714 388.505 291.118 397.451C269.522 406.396 246.375 411 223 411V466C253.598 466 283.896 459.973 312.165 448.264C340.434 436.555 366.12 419.392 387.756 397.756C409.392 376.12 426.555 350.434 438.264 322.165C449.973 293.896 456 263.598 456 233C456 202.402 449.973 172.104 438.264 143.835C426.555 115.566 409.392 89.88 387.756 68.2441C366.12 46.6081 340.434 29.4454 312.165 17.7361C283.896 6.0267 253.598 0 223 0V55ZM215 163C224.193 163 233.295 164.811 241.788 168.328C250.281 171.846 257.997 177.002 264.497 183.503C270.998 190.003 276.154 197.719 279.672 206.212C283.189 214.705 285 223.807 285 233C285 242.193 283.189 251.295 279.672 259.788C276.154 268.281 270.998 275.997 264.497 282.497C257.997 288.998 250.281 294.154 241.788 297.672C233.295 301.189 224.193 303 215 303H124.071L182.984 239.823C184.84 237.833 185.728 235.288 185.668 232.768C185.745 230.225 184.858 227.652 182.986 225.644L124.57 163H215Z"
fill="currentColor"
/>
</SvgIcon>
);
36 changes: 36 additions & 0 deletions src/icons/RightArrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable react/display-name */
import * as React from 'react';

import { styled, SvgIconConfig } from 'stitches.config';

import { IconProps } from 'types';

export const RightArrowIcon = styled(
React.forwardRef<SVGSVGElement, IconProps>(
({ color = 'currentColor', ...props }, forwardedRef) => {
return (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
ref={forwardedRef}
>
<path
d="M6 2L12 8L6 14"
fill="none"
stroke={color}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
),
SvgIconConfig
);

export default RightArrowIcon;
2 changes: 2 additions & 0 deletions src/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export * from './DocsIcon';
export * from './FilterIcon';
export * from './MediumIcon';
export * from './TwitterIcon';
export * from './DeworkIcon';
export * from './DiscordIcon';
export * from './BalanceIcon';
export * from './DeleteIcon';
Expand All @@ -25,6 +26,7 @@ export * from './UploadIcon';
export * from './MinusCircleIcon';
export * from './InfoIcon';
export * from './DownArrow';
export * from './RightArrow';
export * from './GithubIcon';
export * from './TelegramIcon';
export * from './LinkIcon';
Expand Down
58 changes: 55 additions & 3 deletions src/pages/AdminPage/AdminCircleModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,19 @@ import { transparentize } from 'polished';

import { makeStyles, Button } from '@material-ui/core';

import { ApeAvatar, FormModal, ApeTextField, ApeToggle } from 'components';
import {
ApeAvatar,
FormModal,
ApeTextField,
ApeToggle,
ApeInfoTooltip,
} from 'components';
import { DEWORK_APP_INSTALL_URL } from 'config/env';
import { useApiAdminCircle } from 'hooks';
import { UploadIcon, EditIcon } from 'icons';
import { DeworkIcon } from 'icons/DeworkIcon';
import { useSelectedCircle } from 'recoilState/app';
import { getDeworkCallbackPath } from 'routes/paths';
import { getCircleAvatar } from 'utils/domain';

import { ICircle } from 'types';
Expand Down Expand Up @@ -132,6 +141,11 @@ const useStyles = makeStyles(theme => ({
textAlign: 'center',
color: theme.colors.linkBlue,
},
completedWorkContainer: {
display: 'grid',
placeItems: 'center',
marginBottom: theme.spacing(2),
},
}));

const YesNoTooltip = ({ yes = '', no = '', href = '', anchorText = '' }) => {
Expand Down Expand Up @@ -192,6 +206,9 @@ export const AdminCircleModal = ({
const [vouchingText, setVouchingText] = useState(circle.vouchingText);
const [onlyGiverVouch, setOnlyGiverVouch] = useState(circle.only_giver_vouch);
const [autoOptOut, setAutoOptOut] = useState(circle.auto_opt_out);
const [deworkOrganizationId, setDeworkOrganizationId] = useState(
circle.dework_organization_id
);

// onChange Logo
const onChangeLogo = (e: React.ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -251,7 +268,8 @@ export const AdminCircleModal = ({
vouchingText !== circle.vouchingText ||
onlyGiverVouch !== circle.only_giver_vouch ||
teamSelection !== circle.team_selection ||
autoOptOut !== circle.auto_opt_out
autoOptOut !== circle.auto_opt_out ||
deworkOrganizationId !== circle.dework_organization_id
) {
await updateCircle({
name: circleName,
Expand All @@ -268,6 +286,7 @@ export const AdminCircleModal = ({
only_giver_vouch: onlyGiverVouch,
team_selection: teamSelection,
auto_opt_out: autoOptOut,
dework_organization_id: deworkOrganizationId,
}).then(() => {
onClose();
});
Expand All @@ -292,7 +311,8 @@ export const AdminCircleModal = ({
vouchingText !== circle.vouchingText ||
onlyGiverVouch !== circle.only_giver_vouch ||
teamSelection !== circle.team_selection ||
autoOptOut !== circle.auto_opt_out;
autoOptOut !== circle.auto_opt_out ||
deworkOrganizationId !== circle.dework_organization_id;
return (
<FormModal
title="Edit Circle Settings"
Expand Down Expand Up @@ -450,6 +470,38 @@ export const AdminCircleModal = ({
label="Auto Opt Out?"
/>
</div>
<div className={classes.completedWorkContainer}>
<div>
<p className={classes.subTitle}>
Show List of Completed Work
<ApeInfoTooltip>
Connect to Dework to show a list of tasks each contributor has
done during an epoch
</ApeInfoTooltip>
</p>
</div>
{deworkOrganizationId ? (
<Button
variant="contained"
size="small"
startIcon={<DeworkIcon />}
onClick={() => setDeworkOrganizationId(null)}
>
Disconnect Dework
</Button>
) : (
<Button
variant="contained"
size="small"
startIcon={<DeworkIcon />}
href={`${DEWORK_APP_INSTALL_URL}?redirect=${
window.location.origin
}${getDeworkCallbackPath()}`}
>
Connect Dework
</Button>
)}
</div>
<div className={classes.bottomContainer}>
<p className={classes.subTitle}>Discord Webhook</p>
{allowEdit && (
Expand Down
37 changes: 37 additions & 0 deletions src/pages/DeworkCallbackPage/DeworkCallbackPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FC, useCallback, useEffect, useMemo } from 'react';

import { useHistory, useLocation } from 'react-router-dom';

import { useApiAdminCircle } from 'hooks';
import { useCircle, useSelectedCircle } from 'recoilState';
import { getCirclesPath } from 'routes/paths';

export const DeworkCallbackPage: FC = () => {
const history = useHistory();
const { search } = useLocation();
const deworkOrganizationId = useMemo(
() => new URLSearchParams(search).get('dework_organization_id'),
[search]
);

const { circleId } = useSelectedCircle();
const { circle } = useCircle(circleId);
const { updateCircle } = useApiAdminCircle(circleId);

const updateDeworkOrganizationId = useCallback(async () => {
if (deworkOrganizationId) {
await updateCircle({
...circle,
token_name: circle.tokenName,
update_webhook: 0,
dework_organization_id: deworkOrganizationId,
});
}

history.replace(getCirclesPath());
}, []);
useEffect(() => {
updateDeworkOrganizationId();
}, []);
return null;
};
Loading