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

[stable7.3] Cherry pick badge fixes #8602

Merged
merged 3 commits into from
Nov 17, 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
8 changes: 7 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,10 @@ const copySkillmapHtml = () => rimraf("webapp/public/skillmap.html")

const skillmap = gulp.series(cleanSkillmap, buildSkillmap, gulp.series(copySkillmapCss, copySkillmapJs, copySkillmapHtml));

const buildSkillmapTests = () => compileTsProject("skillmap/tests", "built/tests");
const runSkillmapTests = () => exec("./node_modules/.bin/mocha ./built/tests/tests/skillmapParser.spec.js", true)

const testSkillmap = gulp.series(buildSkillmapTests, runSkillmapTests);

/********************************************************
Tests and Linting
Expand Down Expand Up @@ -652,7 +656,8 @@ const testAll = gulp.series(
testpytraces,
testtutorials,
testlanguageservice,
karma
karma,
testSkillmap
)

function testTask(testFolder, testFile) {
Expand Down Expand Up @@ -723,6 +728,7 @@ exports.webapp = gulp.series(
browserifyWebapp
)

exports.skillmapTest = testSkillmap;
exports.updatestrings = updatestrings;
exports.updateblockly = copyBlockly;
exports.lint = lint
Expand Down
1 change: 1 addition & 0 deletions localtypings/pxtarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,7 @@ declare namespace pxt.auth {
type: BadgeType;
title: string;
image: string;
lockedImage?: string;
timestamp?: number;
}

Expand Down
8 changes: 5 additions & 3 deletions react-common/components/profile/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ export const Badge = (props: BadgeProps) => {
onClick(badge);
})

const image = (disabled && badge.lockedImage) || badge.image;
const alt = disabled ? pxt.U.lf("Locked '{0}' badge", badge.title) : badge.title;

return (
<div className={`profile-badge ${disabled ? "disabled" : ""} ${onClick ? "clickable" : ""}`}
<div className={`profile-badge ${onClick ? "clickable" : ""}`}
role={onClick ? "button" : undefined}
tabIndex={onClick ? 0 : undefined}
title={lf("{0} Badge", badge.title)}
onClick={onBadgeClick}
onKeyDown={fireClickOnEnter}>
{isNew && <div className="profile-badge-notification">{pxt.U.lf("New!")}</div>}
<img src={badge.image} alt={badge.title} />
{disabled && <i className="ui huge icon lock" />}
<img src={image} alt={alt} />
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion react-common/components/profile/BadgeInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const badgeDescription = (badge: pxt.auth.Badge) => {
case "skillmap-completion":
return <span>{jsxLF(
lf("Completing {0}"),
<a target="_blank" href={sourceURLToSkillmapURL(badge.sourceURL)}>{pxt.U.rlf(badge.title)}</a>
<a target="_blank" rel="noopener noreferrer" href={sourceURLToSkillmapURL(badge.sourceURL)}>{pxt.U.rlf(badge.title)}</a>
)}</span>
}
}
Expand Down
6 changes: 1 addition & 5 deletions react-common/styles/profile/profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,6 @@
}


.profile-badge.disabled img {
filter: grayscale(1);
opacity: 0.5;
}

.profile-badge.disabled i.ui.icon {
line-height: 1;
vertical-align: middle;
Expand Down Expand Up @@ -280,6 +275,7 @@
margin-right: 0;
text-align: center;
color: var(--header-text-color);
overflow: hidden;
}

.profile-initials-portrait {
Expand Down
1 change: 1 addition & 0 deletions skillmap/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ module.exports = {
"parserOptions": {
"project": "skillmap/tsconfig.json",
},
"ignorePatterns": ["tests/**/*.spec.ts", "public/**/*", "build/**/*"]
}
22 changes: 10 additions & 12 deletions skillmap/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ interface AppState {
error?: string;
cloudSyncCheckHasFinished: boolean;
badgeSyncLock: boolean;
syncingLocalState?: boolean;
showingSyncLoader?: boolean;
}

class AppImpl extends React.Component<AppProps, AppState> {
Expand Down Expand Up @@ -235,9 +235,8 @@ class AppImpl extends React.Component<AppProps, AppState> {
protected async cloudSyncCheckAsync() {
const res = await this.ready();
if (!await authClient.loggedInAsync()) {
this.setState({cloudSyncCheckHasFinished: true, syncingLocalState: false});
this.setState({cloudSyncCheckHasFinished: true});
} else {
this.setState({syncingLocalState: true});
const doCloudSyncCheckAsync = async () => {
const state = store.getState();
const localUser = await getLocalUserStateAsync();
Expand Down Expand Up @@ -315,14 +314,14 @@ class AppImpl extends React.Component<AppProps, AppState> {
action: "requestprojectcloudstatus",
headerIds: getFlattenedHeaderIds(currentUser, state.pageSourceUrl)
} as pxt.editor.EditorMessageRequestProjectCloudStatus);
this.setState({cloudSyncCheckHasFinished: true, syncingLocalState: false});
this.setState({ cloudSyncCheckHasFinished: true, showingSyncLoader: false });
}
// Timeout if cloud sync check doesn't complete in a reasonable timeframe.
const TIMEOUT_MS = 10 * 1000;
await Promise.race([
pxt.U.delay(TIMEOUT_MS).then(() => {
if (!this.state.cloudSyncCheckHasFinished)
this.setState({cloudSyncCheckHasFinished: true, syncingLocalState: false});
this.setState({ cloudSyncCheckHasFinished: true, showingSyncLoader: false });
}),
doCloudSyncCheckAsync()]);
}
Expand All @@ -343,6 +342,10 @@ class AppImpl extends React.Component<AppProps, AppState> {
await this.initLocalizationAsync();
await this.parseHashAsync();
this.readyPromise.setAppMounted();

if (await authClient.loggedInAsync() && !this.state.cloudSyncCheckHasFinished) {
this.setState({ showingSyncLoader: true });
}
}

componentWillUnmount() {
Expand All @@ -354,11 +357,11 @@ class AppImpl extends React.Component<AppProps, AppState> {

render() {
const { skillMaps, activityOpen, backgroundImageUrl, theme } = this.props;
const { error, syncingLocalState } = this.state;
const { error, showingSyncLoader } = this.state;
const maps = Object.keys(skillMaps).map((id: string) => skillMaps[id]);
return (<div className={`app-container ${pxt.appTarget.id}`}>
<HeaderBar />
{syncingLocalState && <div className={"makecode-frame-loader"}>
{showingSyncLoader && <div className={"makecode-frame-loader"}>
<img src={resolvePath("assets/logo.svg")} alt={lf("MakeCode Logo")} />
<div className="makecode-frame-loader-text">{lf("Saving to cloud...")}</div>
</div>}
Expand Down Expand Up @@ -433,11 +436,6 @@ class AppImpl extends React.Component<AppProps, AppState> {
}
}

if ((!this.props.signedIn || (this.props.signedIn && this.state.cloudSyncCheckHasFinished))
&& this.state.syncingLocalState) {
this.setState({ syncingLocalState: false });
}

await this.syncBadgesAsync();
}

Expand Down
9 changes: 7 additions & 2 deletions skillmap/src/components/AppModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,11 @@ export class AppModalImpl extends React.Component<AppModalProps, AppModalState>

return <Modal title={title} onClose={this.handleOnClose} actions={buttons}>
{lf("Use the button below to get your completion certificate!")}
{reward.previewUrl &&
<div className="certificate-reward">
<img src={reward.previewUrl} alt={lf("certificate Preview")} />
</div>
}
</Modal>
}

Expand All @@ -523,7 +528,7 @@ export class AppModalImpl extends React.Component<AppModalProps, AppModalState>
if (signedIn) {
message = jsxLF(
lf("You’ve received the {0} Badge! Find it in the badges section of your {1}."),
<span>{pxt.U.rlf(skillMap!.displayName)}</span>,
<span>{pxt.U.rlf(badge!.title)}</span>,
<a onClick={goToBadges}>{lf("User Profile")}</a>
);
buttons.push(
Expand Down Expand Up @@ -570,10 +575,10 @@ export class AppModalImpl extends React.Component<AppModalProps, AppModalState>


return <Modal title={title} onClose={this.handleOnClose} actions={buttons}>
{message}
<div className="badge-modal-image">
<Badge badge={badge!} />
</div>
{message}
</Modal>
}
}
Expand Down
2 changes: 2 additions & 0 deletions skillmap/src/lib/skillMap.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ type MapReward = MapRewardCertificate | MapCompletionBadge;
interface MapRewardCertificate {
type: "certificate";
url: string;
previewUrl?: string;
}

interface MapCompletionBadge {
type: "completion-badge";
imageUrl: string;
displayName?: string;
}

interface MapRewardNode extends BaseNode {
Expand Down
Loading