Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Added XP progress task list for quests #10591

Merged
merged 4 commits into from
Jan 23, 2025
Merged
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
31 changes: 31 additions & 0 deletions packages/commonwealth/client/scripts/state/api/user/getXPs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { GetXps } from '@hicommonwealth/schemas';
import { trpc } from 'utils/trpcClient';
import { z } from 'zod';

type UseGetXPsProps = z.infer<typeof GetXps.input> & {
enabled?: boolean;
};

const useGetXPs = ({
community_id,
event_name,
from,
to,
user_id,
enabled = true,
}: UseGetXPsProps) => {
return trpc.user.getXps.useQuery(
{
community_id,
event_name,
from,
to,
user_id,
},
{
enabled,
},
);
};

export default useGetXPs;
2 changes: 2 additions & 0 deletions packages/commonwealth/client/scripts/state/api/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCreateApiKeyMutation } from './createApiKey';
import { useDeleteApiKeyMutation } from './deleteApiKey';
import { useGetApiKeyQuery } from './getApiKey';
import useGetNewContent from './getNewContent';
import useGetXPs from './getXPs';
import useUpdateUserActiveCommunityMutation from './updateActiveCommunity';
import useUpdateUserEmailMutation from './updateEmail';
import useUpdateUserEmailSettingsMutation from './updateEmailSettings';
Expand All @@ -13,6 +14,7 @@ export {
useDeleteApiKeyMutation,
useGetApiKeyQuery,
useGetNewContent,
useGetXPs,
useSignIn,
useUpdateUserActiveCommunityMutation,
useUpdateUserEmailMutation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export const Select = ({
return (
<ClickAwayListener
onClickAway={async () => {
// @ts-expect-error <StrictNullChecks/>
popoverProps.setAnchorEl(null);
onClose && (await onClose());
}}
Expand Down Expand Up @@ -129,7 +128,6 @@ export const Select = ({
e.preventDefault();
// @ts-expect-error <StrictNullChecks/>
onSelect(option);
// @ts-expect-error <StrictNullChecks/>
popoverProps.setAnchorEl(null);
onClose && (await onClose());
}}
Expand All @@ -143,7 +141,6 @@ export const Select = ({
iconSize="small"
onClick={(e) => {
e.stopPropagation();
// @ts-expect-error <StrictNullChecks/>
popoverProps.setAnchorEl(null);
onOptionEdit?.(option);
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@import '../../../../../../../styles/shared';

.QuestTask {
all: unset;
display: grid;
grid-template-columns: 1fr 5fr;
width: 100%;
gap: 12px;
cursor: pointer;
border-radius: 8px;

&:hover {
background-color: $neutral-100;
}

&:focus,
&:focus-within {
outline: none;
}

.left {
padding: 16px 4px 16px 12px;
display: flex;
align-items: center;
justify-content: center;
width: 100%;

img {
width: 44px;
height: 44px;
object-fit: cover;
border-radius: 6px;
}
}

.right {
padding: 12px 16px 12px 0;
display: flex;
flex-direction: column;
gap: 4px;
justify-content: center;
width: 100%;

.xp-row {
display: flex;
justify-content: space-between;
align-items: center;

.days-left {
color: $primary-300 !important;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import clsx from 'clsx';
import React from 'react';

import { CWText } from 'views/components/component_kit/cw_text';
import { CWTag } from 'views/components/component_kit/new_designs/CWTag';
import './QuestTask.scss';

type QuestTaskProps = {
className?: string;
onClick: () => void;
quest: {
imageURL: string;
title: string;
xpPoints: number;
daysLeftBeforeEnd: number;
};
};

const QuestTask = ({ className, quest, onClick }: QuestTaskProps) => {
return (
<button className={clsx('QuestTask', className)} onClick={onClick}>
<div className="left">
<img src={quest.imageURL} />
</div>
<div className="right">
<CWText type="b1">{quest.title}</CWText>
<div className="xp-row">
<CWTag label={`${quest.xpPoints} XP`} type="proposal" />
<CWText type="caption" className="days-left" fontWeight="semiBold">
{quest.daysLeftBeforeEnd} days left
</CWText>
</div>
</div>
</button>
);
};

export default QuestTask;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import QuestTask from './QuestTask';

export default QuestTask;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@import '../../../../../../styles/shared';

.Quests {
width: 100%;
display: flex;
flex-direction: column;
padding: 8px 0px;

.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 0 4px 4px 18px;

.b1 {
color: $neutral-400 !important;
}
}

.list {
width: 100%;
display: flex;
flex-direction: column;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import clsx from 'clsx';
import React from 'react';

import { CWText } from 'client/scripts/views/components/component_kit/cw_text';
import { CWButton } from 'client/scripts/views/components/component_kit/new_designs/CWButton';
import QuestTask from './QuestTask';
import './Quests.scss';

type QuestsProps = {
className?: string;
quests: {
id: number;
imageURL: string;
xpPoints: number;
title: string;
daysLeftBeforeEnd: number;
}[];
};

const Quests = ({ className, quests }: QuestsProps) => {
const handleSeeAllQuests = () => {
// TODO: navigate to quests page
};

return (
<div className={clsx('Quests', className)}>
<div className="header">
<CWText type="b1" fontWeight="semiBold">
Weekly Quests
</CWText>
<CWButton
label="See all"
iconRight="arrowRight"
buttonHeight="sm"
buttonWidth="narrow"
buttonType="tertiary"
onClick={handleSeeAllQuests}
/>
</div>
<div className="list">
{quests.map((quest) => (
<QuestTask key={quest.id} quest={quest} onClick={() => {}} />
))}
</div>
</div>
);
};

export default Quests;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Quests from './Quests';

export default Quests;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@import '../../../../../styles/shared';

.TaskList {
width: 300px;
background-color: $white;
border: 1px solid $neutral-200;
border-radius: 8px;
box-shadow: $elevation-4 !important;
margin-top: 4px;
z-index: 999;

.weekly-progress-bar {
width: 100% !important;
min-width: unset;
max-width: unset;
padding: 16px 12px 8px 12px;
}

@include extraSmall {
width: 100%;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import clsx from 'clsx';
import React from 'react';

import useBrowserWindow from 'hooks/useBrowserWindow';
import moment from 'moment';
import { useGetXPs } from 'state/api/user';
import useUserStore from 'state/ui/user';
import WeeklyProgressGoal from '../WeeklyProgressGoal';
import Quests from './Quests';
import './TaskList.scss';

type TaskListProps = {
className?: string;
};

const TaskList = ({ className }: TaskListProps) => {
const { isWindowExtraSmall } = useBrowserWindow({});

const sampleData = {
weeklyGoal: {
current: 170,
target: 400,
},
};

const user = useUserStore();
const { data = [], isLoading } = useGetXPs({
user_id: user.id,
from: moment().startOf('week').toDate(),
to: moment().endOf('week').toDate(),
enabled: user.isLoggedIn,
});

if (isLoading) return;

return (
<div className={clsx('TaskList', className)}>
{isWindowExtraSmall && (
<WeeklyProgressGoal
className="weekly-progress-bar"
progress={sampleData.weeklyGoal}
/>
)}
<Quests
quests={data
.filter((task) => task.quest_id)
.map((task) => ({
daysLeftBeforeEnd: 4, // TODO: where to get time diff from
id: task.quest_id || 0,
// TODO: where to get this url from
imageURL:
'https://cdn.pixabay.com/photo/2023/01/08/14/22/sample-7705350_640.jpg',
title: task.event_name,
xpPoints: task.xp_points,
}))}
/>
</div>
);
};

export default TaskList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import TaskList from './TaskList';

export default TaskList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@import '../../../../../styles/shared';

.WeeklyProgressGoal {
min-width: 150px;
width: 200px;
max-width: 200px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 2px;

.header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 0 4px;

.caption {
font-size: 10px !important;
color: $primary-500 !important;
}
}

.progress-bar {
height: 10px;
width: 100%;
border: 1px solid $neutral-100;

&::-webkit-progress-bar {
background-color: $neutral-200;
border-radius: $border-radius-corners;
}

&::-webkit-progress-value {
background-color: $primary-400;
border-radius: $border-radius-corners;
}
}
}
Loading
Loading