Skip to content

Upgrades to Achievements UI and removal of Achievement categories #1886

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

Merged
merged 5 commits into from
Aug 4, 2021
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
9 changes: 3 additions & 6 deletions src/commons/achievement/AchievementCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function AchievementCard(props: AchievementCardProps) {

const [focusUuid, setFocusUuid] = focusState;

const { ability, cardBackground, title } = inferencer.getAchievement(uuid);
const { cardBackground, title } = inferencer.getAchievement(uuid);
const displayDeadline = inferencer.getDisplayDeadline(uuid);
const displayXp = inferencer.getAchievementXp(uuid);
const progressFrac = inferencer.getProgressFrac(uuid);
Expand All @@ -38,7 +38,7 @@ function AchievementCard(props: AchievementCardProps) {
onClick={() => setFocusUuid(uuid)}
onClickCapture={toggleDropdown}
style={{
...handleGlow(uuid, focusUuid, ability),
...handleGlow(uuid, focusUuid),
opacity: shouldRender ? '100%' : '20%',
background: `url(${cardBackground}) center/cover`
}}
Expand All @@ -58,10 +58,7 @@ function AchievementCard(props: AchievementCardProps) {
</div>

<div className="details">
<div className="ability">
<p>{ability}</p>
</div>
<AchievementDeadline ability={ability} deadline={displayDeadline} />
<AchievementDeadline deadline={displayDeadline} />
<AchievementXp isBonus={hasDropdown} xp={displayXp} />
</div>

Expand Down
58 changes: 43 additions & 15 deletions src/commons/achievement/AchievementManualEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Button, MenuItem, NumericInput } from '@blueprintjs/core';
import { ItemRenderer, Select } from '@blueprintjs/select';
import { Button, Checkbox, MenuItem, NumericInput } from '@blueprintjs/core';
import { ItemPredicate, ItemRenderer, Select } from '@blueprintjs/select';
import { useContext, useEffect, useState } from 'react';
import { AchievementContext } from 'src/features/achievement/AchievementConstants';
import {
Expand All @@ -8,7 +8,11 @@ import {
GoalProgress
} from 'src/features/achievement/AchievementTypes';

import { showSuccessMessage, showWarningMessage } from '../utils/NotificationsHelper';

type AchievementManualEditorProps = {
hiddenState: [boolean, any];
userState: [AchievementUser | undefined, any];
studio: string;
users: AchievementUser[];
getUsers: () => void;
Expand All @@ -19,9 +23,22 @@ const GoalSelect = Select.ofType<AchievementGoal>();
const goalRenderer: ItemRenderer<AchievementGoal> = (goal, { handleClick }) => (
<MenuItem key={goal.uuid} onClick={handleClick} text={goal.text} />
);
const goalPredicate: ItemPredicate<AchievementGoal> = (query, item) =>
item.text.toLowerCase().includes(query.toLowerCase());

const UserSelect = Select.ofType<AchievementUser>();
const userRenderer: ItemRenderer<AchievementUser> = (user, { handleClick }) => (
<MenuItem key={user.courseRegId} onClick={handleClick} text={user.name} />
);
const userPredicate: ItemPredicate<AchievementUser> = (query, item) =>
item.name.toLowerCase().includes(query.toLowerCase());

export function updateGoalProcessed() {
showSuccessMessage('Goal updated');
}

function AchievementManualEditor(props: AchievementManualEditorProps) {
const { studio, getUsers, updateGoalProgress } = props;
const { userState, hiddenState, studio, getUsers, updateGoalProgress } = props;
const users =
studio === 'Staff'
? // The name can be null for users who have yet to log in. We push these to the back of the array.
Expand All @@ -39,35 +56,36 @@ function AchievementManualEditor(props: AchievementManualEditorProps) {
.getAllGoals()
.filter(goals => goals.meta.type === 'Manual');

const [goal, changeGoal] = useState(manualAchievements[0]);
const [selectedUser, changeSelectedUser] = useState(users[0]);
const [count, changeCount] = useState(0);

const UserSelect = Select.ofType<AchievementUser>();
const userRenderer: ItemRenderer<AchievementUser> = (user, { handleClick }) => (
<MenuItem key={user.courseRegId} onClick={handleClick} text={user.name} />
);
const [goal, changeGoal] = useState<AchievementGoal | undefined>(undefined);
const [selectedUser, changeSelectedUser] = userState;
const [count, changeCount] = useState<number>(0);
const [viewHidden, changeViewHidden] = hiddenState;

const updateGoal = () => {
if (goal) {
if (goal && selectedUser) {
const progress: GoalProgress = {
uuid: goal.uuid,
count: count,
count: count < 0 ? 0 : Math.floor(count),
targetCount: goal.targetCount,
completed: count >= goal.targetCount
};
updateGoalProgress(selectedUser.courseRegId, progress);
} else {
!goal && showWarningMessage('Goal not selected');
!selectedUser && showWarningMessage('User not selected');
}
};

return (
<div className="achievement-manual-editor">
<h3>User: </h3>
<UserSelect
filterable={false}
filterable={true}
items={users}
itemRenderer={userRenderer}
itemPredicate={userPredicate}
onItemSelect={changeSelectedUser}
noResults={<MenuItem disabled={true} text="No matching user" />}
>
<Button
outlined={true}
Expand All @@ -78,10 +96,12 @@ function AchievementManualEditor(props: AchievementManualEditorProps) {

<h3>Goal: </h3>
<GoalSelect
filterable={false}
filterable={true}
items={manualAchievements}
itemRenderer={goalRenderer}
itemPredicate={goalPredicate}
onItemSelect={changeGoal}
noResults={<MenuItem disabled={true} text="No matching goal" />}
>
<Button outlined={true} text={goal ? goal.text : 'No Goal Selected'} color="White" />
</GoalSelect>
Expand All @@ -91,12 +111,20 @@ function AchievementManualEditor(props: AchievementManualEditorProps) {
value={count}
min={0}
allowNumericCharactersOnly={true}
minorStepSize={null}
placeholder="Count"
onValueChange={changeCount}
/>

<h3> </h3>
<Button outlined={true} text="Update Goal" onClick={updateGoal} intent="primary" />

<h3> </h3>
<Checkbox
checked={viewHidden}
label="View Hidden Achievements"
onChange={() => changeViewHidden(!viewHidden)}
/>
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/commons/achievement/AchievementTask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function AchievementTask(props: AchievementTaskProps) {

const inferencer = useContext(AchievementContext);
const prerequisiteUuids = [...inferencer.getImmediateChildren(uuid)];
const taskColor = getAbilityColor(inferencer.getAchievement(uuid).ability);
const taskColor = getAbilityColor();

const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
const toggleDropdown = () => setIsDropdownOpen(!isDropdownOpen);
Expand Down
7 changes: 4 additions & 3 deletions src/commons/achievement/AchievementView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ function AchievementView(props: AchievementViewProps) {
}

const achievement = inferencer.getAchievement(focusUuid);
const { ability, deadline, title, view } = achievement;
const { deadline, title, view } = achievement;
const { coverImage, completionText, description } = view;
const awardedXp = inferencer.getAchievementXp(focusUuid);
const goals = inferencer.listGoals(focusUuid);
const prereqGoals = inferencer.listPrerequisiteGoals(focusUuid);
const status = inferencer.getStatus(focusUuid);

return (
<div className="view" style={{ ...getAbilityGlow(ability), ...getAbilityBackground(ability) }}>
<div className="view" style={{ ...getAbilityGlow(), ...getAbilityBackground() }}>
<div
className="cover"
style={{
background: `url(${coverImage}) center/cover`
background: `rgba(0, 0, 0, 0.5) url(${coverImage}) center/cover`,
backgroundBlendMode: `darken`
}}
>
<h1>{title.toUpperCase()}</h1>
Expand Down
9 changes: 2 additions & 7 deletions src/commons/achievement/card/AchievementDeadline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,20 @@ import { Icon } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';

import { DeadlineColors } from '../../../features/achievement/AchievementConstants';
import { AchievementAbility } from '../../../features/achievement/AchievementTypes';
import { isExpired, prettifyDeadline, timeFromExpired } from '../utils/DateHelper';

type AchievementDeadlineProps = {
ability: AchievementAbility;
deadline?: Date;
};

const twoDays = new Date(0, 0, 2).getTime() - new Date(0, 0, 0).getTime();

function AchievementDeadline(props: AchievementDeadlineProps) {
const { ability, deadline } = props;
const { deadline } = props;

// red deadline color for core achievements that are expiring in less than 2 days
const deadlineColor =
ability === AchievementAbility.CORE &&
deadline !== undefined &&
!isExpired(deadline) &&
timeFromExpired(deadline) <= twoDays
deadline !== undefined && !isExpired(deadline) && timeFromExpired(deadline) <= twoDays
? DeadlineColors.RED
: DeadlineColors.BLACK;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Dialog, EditableText } from '@blueprintjs/core';
import { Button, Checkbox, Dialog, EditableText } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { Tooltip2 } from '@blueprintjs/popover2';
import { useState } from 'react';
Expand Down Expand Up @@ -58,9 +58,13 @@ function AchievementSettings(props: AchievementSettingsProps) {
/>
<h3>Goals</h3>
<EditableGoalUuids changeGoalUuids={changeGoalUuids} goalUuids={goalUuids} />
<Tooltip2 content="The rewarded XP will be equal to the sum of 'count' of goals">
<Button text={'Variable XP?'} active={isVariableXp} onClick={changeIsVariableXp} />
</Tooltip2>

<h3>Variable XP</h3>
<Checkbox
label={"The rewarded XP will be equal to the sum of 'count' of goals"}
checked={isVariableXp}
onChange={changeIsVariableXp}
/>
</div>
</Dialog>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
coverImageUrl
} from '../../../../features/achievement/AchievementConstants';
import {
AchievementAbility,
AchievementItem,
AchievementView
} from '../../../../features/achievement/AchievementTypes';
Expand All @@ -17,7 +16,6 @@ export const viewTemplate: AchievementView = {
export const achievementTemplate: AchievementItem = {
uuid: '',
title: 'Achievement Title Here',
ability: AchievementAbility.CORE,
xp: 0,
isVariableXp: false,
isTask: false,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ import { useContext, useMemo, useReducer, useState } from 'react';

import { AchievementContext } from '../../../../features/achievement/AchievementConstants';
import {
AchievementAbility,
AchievementItem,
AchievementView
} from '../../../../features/achievement/AchievementTypes';
import ItemDeleter from '../common/ItemDeleter';
import ItemSaver from '../common/ItemSaver';
import AchievementSettings from './AchievementSettings';
import EditableAbility from './EditableAbility';
import {
EditableCardAction as Action,
EditableCardActionType as ActionType,
Expand Down Expand Up @@ -51,14 +49,6 @@ const reducer = (state: State, action: Action) => {
...state,
isDirty: false
};
case ActionType.CHANGE_ABILITY:
return {
editableAchievement: {
...state.editableAchievement,
ability: action.payload
},
isDirty: true
};
case ActionType.CHANGE_CARD_BACKGROUND:
return {
editableAchievement: {
Expand Down Expand Up @@ -155,7 +145,7 @@ function EditableCard(props: EditableCardProps) {
const [state, dispatch] = useReducer(reducer, achievementClone, init);
const [isNew, setIsNew] = useState<boolean>(isNewAchievement);
const { editableAchievement, isDirty } = state;
const { ability, cardBackground, deadline, release, title, view, xp } = editableAchievement;
const { cardBackground, deadline, release, title, view, xp } = editableAchievement;

const saveChanges = () => {
dispatch({ type: ActionType.SAVE_CHANGES });
Expand All @@ -181,9 +171,6 @@ function EditableCard(props: EditableCardProps) {
requestPublish();
};

const changeAbility = (ability: AchievementAbility) =>
dispatch({ type: ActionType.CHANGE_ABILITY, payload: ability });

const changeCardBackground = (cardBackground: string) =>
dispatch({ type: ActionType.CHANGE_CARD_BACKGROUND, payload: cardBackground });

Expand Down Expand Up @@ -245,7 +232,6 @@ function EditableCard(props: EditableCardProps) {
</Tooltip2>
</div>
<div className="details">
<EditableAbility ability={ability} changeAbility={changeAbility} />
<EditableDate changeDate={changeRelease} date={release} type="Release" />
<EditableDate changeDate={changeDeadline} date={deadline} type="Deadline" />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import {
AchievementAbility,
AchievementItem,
AchievementView
} from 'src/features/achievement/AchievementTypes';
import { AchievementItem, AchievementView } from 'src/features/achievement/AchievementTypes';

export enum EditableCardActionType {
CHANGE_ABILITY = 'CHANGE_ABILITY',
CHANGE_CARD_BACKGROUND = 'CHANGE_CARD_BACKGROUND',
CHANGE_DEADLINE = 'CHANGE_DEADLINE',
CHANGE_GOAL_UUIDS = 'CHANGE_GOAL_UUIDS',
Expand All @@ -22,10 +17,6 @@ export enum EditableCardActionType {
}

export type EditableCardAction =
| {
type: EditableCardActionType.CHANGE_ABILITY;
payload: AchievementAbility;
}
| {
type: EditableCardActionType.CHANGE_CARD_BACKGROUND;
payload: string;
Expand Down
Loading