Skip to content

Commit c8a595e

Browse files
author
smallst_wsl
committed
Merge remote-tracking branch 'origin/master' into yuqiang/new-dashboard-customized-license-modal
2 parents 0831806 + 1ccc7db commit c8a595e

31 files changed

+490
-531
lines changed
113 KB
Loading
112 KB
Loading

app/core/store/modules/prepaids.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,10 @@ export default {
445445
await new Promise((resolve, reject) =>
446446
prepaid.revoke(student, {
447447
success: resolve,
448-
error: reject,
448+
error: (_p, e) => {
449+
noty({ text: e?.responseJSON?.message || 'The revocation of the license failed', type: 'error' })
450+
return reject(e)
451+
},
449452
data: { sharedClassroomId },
450453
}),
451454
)

app/core/utils.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,11 +1345,11 @@ const arenas = [
13451345
{ season: 12, slug: 'system-shock', type: 'regular', start: new Date('2024-09-01T00:00:00.000-07:00'), end: new Date('2025-01-01T00:00:00.000-08:00'), results: new Date('2025-01-18T07:00:00.000-08:00'), levelOriginal: '66ba09c7c34ab945ba4f52a2', tournament: '66d0b7f11c8954cacec98d47', image: '/file/db/level/66ba09c7c34ab945ba4f52a2/SystemShockBanner2.png' },
13461346
{ season: 12, slug: 'supercharged', type: 'championship', start: new Date('2024-12-01T00:00:00.000-08:00'), end: new Date('2025-01-01T00:00:00.000-08:00'), results: new Date('2025-01-14T07:00:00.000-08:00'), levelOriginal: '66f545e57e91e7168c3e463c', tournament: '6756bac52bfcb2c7059f3cb3', image: '/file/db/level/66f545e57e91e7168c3e463c/superchargedbanner2.jpg' },
13471347
{ season: 13, slug: 'pawns-passage', type: 'regular', start: new Date('2025-01-01T00:00:00.000-08:00'), end: new Date('2025-06-01T00:00:00.000-07:00'), results: new Date('2025-06-14T07:00:00.000-07:00'), levelOriginal: '675a76867ea2b689e0f86e87', image: '/file/db/level/675a76867ea2b689e0f86e87/PawnsPassageBanner.jpg' },
1348-
{ season: 13, slug: 'kings-gambit', type: 'championship', start: new Date('2025-05-01T00:00:00.000-07:00'), end: new Date('2025-06-01T00:00:00.000-07:00'), results: new Date('2025-06-10T07:00:00.000-07:00'), levelOriginal: '', image: '' },
1349-
{ season: 14, slug: 'strikers-stadium', type: 'regular', start: new Date('2025-05-01T00:00:00.000-07:00'), end: new Date('2025-09-01T00:00:00.000-07:00'), results: new Date('2025-09-14T07:00:00.000-07:00'), levelOriginal: '', image: '' },
1350-
{ season: 14, slug: 'golden-goal', type: 'championship', start: new Date('2025-07-01T00:00:00.000-07:00'), end: new Date('2025-09-01T00:00:00.000-07:00'), results: new Date('2025-09-10T07:00:00.000-07:00'), levelOriginal: '', image: '' },
1351-
{ season: 15, slug: 'turbo-track', type: 'regular', start: new Date('2025-09-01T00:00:00.000-07:00'), end: new Date('2026-01-01T00:00:00.000-08:00'), results: new Date('2026-01-14T07:00:00.000-08:00'), levelOriginal: '', image: '' },
1352-
{ season: 15, slug: 'grand-prix', type: 'championship', start: new Date('2025-12-01T00:00:00.000-08:00'), end: new Date('2026-01-01T00:00:00.000-08:00'), results: new Date('2026-01-10T07:00:00.000-08:00'), levelOriginal: '', image: '' },
1348+
{ season: 13, slug: 'kings-gambit', type: 'championship', start: new Date('2025-05-01T00:00:00.000-07:00'), end: new Date('2025-06-01T00:00:00.000-07:00'), results: new Date('2025-06-10T07:00:00.000-07:00'), levelOriginal: '679b1495454eb6d46f27e050', image: '/file/db/level/679b1495454eb6d46f27e050/KingsGambit.jpg' },
1349+
{ season: 14, slug: 'strikers-stadium', type: 'regular', start: new Date('2025-06-01T00:00:00.000-07:00'), end: new Date('2025-08-01T00:00:00.000-07:00'), results: new Date('2025-09-14T07:00:00.000-07:00'), levelOriginal: '', image: '' },
1350+
{ season: 14, slug: 'golden-goal', type: 'championship', start: new Date('2025-06-01T00:00:00.000-07:00'), end: new Date('2025-08-01T00:00:00.000-07:00'), results: new Date('2025-09-14T07:00:00.000-07:00'), levelOriginal: '', image: '' },
1351+
{ season: 15, slug: 'turbo-track', type: 'regular', start: new Date('2025-08-01T00:00:00.000-08:00'), end: new Date('2026-01-01T00:00:00.000-08:00'), results: new Date('2026-01-10T07:00:00.000-08:00'), levelOriginal: '', image: '' },
1352+
{ season: 15, slug: 'grand-prix', type: 'championship', start: new Date('2025-08-01T00:00:00.000-08:00'), end: new Date('2026-01-01T00:00:00.000-08:00'), results: new Date('2026-01-10T07:00:00.000-08:00'), levelOriginal: '', image: '' },
13531353
]
13541354

13551355
// AI League seasons

app/locale/en.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ module.exports = {
342342
coco_worlds_header: 'CodeCombat Worlds',
343343
coco_worlds_description: 'Embark on a 3D coding adventure in Roblox, where you can program pets, play with friends, and develop games all while playing one. Join the CodeCombat community and unleash your creativity in the metaverse!',
344344
coco_worlds_button: 'Explore CodeCombat Worlds',
345+
promo_modal_title: 'CodeCombat Home',
346+
promo_modal_subtitle: 'Learn Real Coding Through Epic Gameplay',
347+
promo_modal_text: 'Dive into real‑world coding with **Python** and **JavaScript**, solving epic puzzles, battling foes, and building a strong coding foundation. Along the way, you’ll learn the skills to **create your own games** and **websites** — all in their browser, no downloads needed.',
345348
},
346349

347350
nav: {
@@ -551,6 +554,11 @@ module.exports = {
551554
locked: 'Locked',
552555
locked_by_teacher: 'Locked By Teacher',
553556
locked_campaign: 'Complete previous world to unlock',
557+
locked_campaign_forest: 'Complete Kithgard Dungeon to unlock',
558+
locked_campaign_desert: 'Complete Backwoods Forest to unlock',
559+
locked_campaign_mountain: 'Complete Sarven Desert to unlock',
560+
locked_campaign_glacier: 'Complete Cloudrip Mountain to unlock',
561+
locked_campaign_volcano: 'Complete Kelvintaph Mountain to unlock',
554562
available: 'Available',
555563
skills_granted: 'Skills Granted', // Property documentation details
556564
heroes: 'Heroes', // Tooltip on hero shop button from /play
@@ -597,10 +605,18 @@ module.exports = {
597605
age_codecombat_junior: 'Ages 5-8',
598606
age_description_codecombat: 'Real Python or JavaScript coding for everyone',
599607
age_description_codecombat_junior: 'Blocks or simple text coding for beginners',
608+
campaign_about_dungeon: 'Real text programming for brave adventurers!',
609+
campaign_about_junior: 'Blocks or simple text coding for young heroes!',
600610
want_more_hints: 'Want more hints?',
601611
choose_your_adventure: 'Choose Your Adventure',
602612
junior: 'Junior',
603613
original: 'Original',
614+
roblox_button_hover: 'Play, Code and Create on Roblox',
615+
ai_league_button_hover: 'Compete in AI League Esports',
616+
hackstack_button_hover: 'Code and Create with AI HackStack',
617+
junior_button_hover: 'Blocks coding for beginners',
618+
cchome_button_hover: 'Original CodeCombat Adventure',
619+
604620
},
605621

606622
code: {
@@ -5808,6 +5824,9 @@ module.exports = {
58085824
faq_7_question: 'Recommended browser and operating system',
58095825
faq_7_answer: 'TBA',
58105826
learn_more: 'Learn More',
5827+
promo_modal_title: 'Explore AI HackStack',
5828+
promo_modal_subtitle: 'Unlock the Full Potential of Generative AI',
5829+
promo_modal_text: '**New to AI? Explore CodeCombat AI HackStack** — the easiest way to dive into AI literacy. Unlock the power of top models like **ChatGPT-4**, **Claude**, **Stable Diffusion**, and **DALL-E**. With hands-on tools, creating games, art, websites, code, and more has never been simpler. It’s the perfect companion for any creative project, no experience required!',
58115830
},
58125831

58135832
standards_page: {
@@ -6410,6 +6429,8 @@ module.exports = {
64106429
faq_4_answer: "Yes. All players can sign-up for free at roblox.com. Don't forget to link your CodeCombat account and Roblox account to access all the features and rewards.",
64116430
faq_5_question: 'Will it work on my Chromebook or mobile device?',
64126431
faq_5_answer: 'Yes. CodeCombat Worlds allows you to play, type real code and create games on PC, Mac, Chromebooks, tablets, phones, and consoles.',
6432+
promo_modal_title: 'Discover CodeCombat Worlds',
6433+
promo_modal_text: '**Want to build a Roblox game but can’t code?** Jump into **CodeCombat Worlds** — where you’ll learn by playing! Start in Rift Village, coding your pets to harvest, and battle. Then tackle Lua (the coding language of Roblox) in the Learning Levels, and finally unleash your ideas in Creative Mode to craft immersive Roblox games. The power to create is in your hands!',
64136434
},
64146435
pd_page: {
64156436
implementation_training_title: 'Implementation Training',
@@ -6474,6 +6495,8 @@ module.exports = {
64746495
get_a_headstart: 'Get a Headstart from Home',
64756496
parents_junior_perfect: 'Parents, CodeCombat Junior is the perfect way to start introducing your child not only to computer science but all the benefits, including problem solving, logic and reasoning, persistence, computational thinking and creative exploration.',
64766497
explore_learning_options: 'Explore Learning Options',
6498+
promo_modal_subtitle: 'Play, Learn, and Grow with Game‑Based Coding',
6499+
promo_modal_text: '**Kickstart their coding adventure with scaffolded levels designed for ages 5–8—no reading or typing needed!** They’ll learn with icon blocks, word blocks, or simple text side by side, and tackle adaptive challenges that keep them engaged. Works seamlessly on **Chromebooks**, **tablets**, and **iPads**.',
64776500
},
64786501
paywall: {
64796502
badge_free: 'Free',

app/models/User.js

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ module.exports = (User = (function () {
300300
}
301301

302302
hasAiJuniorAccess () {
303-
return this.isAdmin() || this.isBetaTester()
303+
return this.isAdmin() || this.isBetaTester() || this.isOnlineTeacher() || !this.isAnonymous()
304304
}
305305

306306
getHocCourseInstanceId () {
@@ -1229,51 +1229,6 @@ module.exports = (User = (function () {
12291229
return value
12301230
}
12311231

1232-
getHackStackExperimentValue () {
1233-
let value = { true: 'beta', false: 'control', control: 'control', beta: 'beta' }[utils.getQueryVariable('hackstack')]
1234-
if (value == null) { value = me.getExperimentValue('hackstack', null, 'beta') }
1235-
if ((value == null) && utils.isOzaria) {
1236-
// Don't include Ozaria for now
1237-
value = 'control'
1238-
}
1239-
if ((value == null) && features?.china) {
1240-
// Don't include China players for now
1241-
value = 'control'
1242-
}
1243-
if (userUtils.isInLibraryNetwork()) {
1244-
value = 'control'
1245-
}
1246-
if ((value == null) && !/^en/.test(me.get('preferredLanguage', true))) {
1247-
// Don't include non-English-speaking users before we fine-tune for other languages
1248-
value = 'control'
1249-
}
1250-
if ((value == null) && me.get('hourOfCode')) {
1251-
// Don't include users coming in through Hour of Code
1252-
value = 'control'
1253-
}
1254-
if ((value == null) && me.get('role')) {
1255-
// Don't include users other than home users
1256-
value = 'control'
1257-
}
1258-
if (me.isAdmin()) {
1259-
value = 'beta'
1260-
}
1261-
if ((!value)) {
1262-
let valueProbability
1263-
const probability = window.serverConfig?.experimentProbabilities?.hackstack?.beta != null ? window.serverConfig.experimentProbabilities.hackstack.beta : 0.05
1264-
if (Math.random() < probability) {
1265-
value = 'beta'
1266-
valueProbability = probability
1267-
} else {
1268-
value = 'control'
1269-
valueProbability = 1 - probability
1270-
}
1271-
console.log('starting hackstack experiment with value', value, 'prob', valueProbability)
1272-
me.startExperiment('hackstack', value, valueProbability)
1273-
}
1274-
return value
1275-
}
1276-
12771232
getJuniorExperimentValue () {
12781233
let value = { true: 'beta', false: 'control', control: 'control', beta: 'beta' }[utils.getQueryVariable('junior')]
12791234
if (value == null) { value = me.getExperimentValue('junior', null, 'beta') }

app/schemas/models/prepaid.schema.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ const PrepaidSchema = c.object({ title: 'Prepaid', required: ['type'] }, {
5050
removedJoiners: c.array({ title: 'Teachers this Prepaid was shared with' },
5151
c.object({ required: ['userID'] },
5252
{ userID: c.objectId({ links: [{ rel: 'extra', href: '/db/user/{($)}' }] }) })
53-
)
53+
),
54+
irrevocable: { type: 'boolean' },
5455
})
5556

5657
c.extendBasicProperties(PrepaidSchema, 'prepaid')
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
@import "app/styles/mixins"
2+
@import "app/styles/bootstrap/variables"
3+
4+
.classic-promotion-modal
5+
6+
//- Clear modal defaults
7+
.modal-dialog
8+
margin: 60px auto 0 auto
9+
padding: 0
10+
width: 746px
11+
height: 520px
12+
background: none
13+
14+
15+
.modal-background
16+
position: absolute
17+
top: -61px
18+
left: 0px
19+
20+
//- Header
21+
h1
22+
position: absolute
23+
left: 170px
24+
top: 25px
25+
margin: 0
26+
width: 410px
27+
text-align: center
28+
color: rgb(254,188,68)
29+
font-size: 32px
30+
text-shadow: black 4px 4px 0, black -4px -4px 0, black 4px -4px 0, black -4px 4px 0, black 4px 0px 0, black 0px -4px 0, black -4px 0px 0, black 0px 4px 0, black 6px 6px 6px
31+
font-variant: normal
32+
text-transform: uppercase
33+
margin-left: -30px
34+
35+
//- Close modal button
36+
37+
.close-modal
38+
position: absolute
39+
left: 568px
40+
top: 17px
41+
width: 60px
42+
height: 60px
43+
color: white
44+
text-align: center
45+
font-size: 30px
46+
padding-top: 15px
47+
cursor: pointer
48+
@include rotate(-3deg)
49+
50+
&:hover
51+
color: yellow
52+
53+
//- Paper area
54+
55+
.paper-area
56+
position: absolute
57+
top: 114px
58+
left: 31px
59+
min-height: 370px
60+
width: 684px
61+
background: #d4c9b1
62+
border: 3px solid black
63+
display: flex
64+
flex-direction: column
65+
justify-content: space-between
66+
padding: 10px
67+
68+
69+
.modal-image-container
70+
margin-left: auto
71+
margin-right: auto
72+
display: flex
73+
justify-content: center
74+
img
75+
width: auto
76+
height: 100%
77+
max-width: 100%
78+
object-fit: contain
79+
80+
.modal-video-container
81+
margin-left: auto
82+
margin-right: auto
83+
width: 70%
84+
position: relative
85+
86+
.video-aspect-ratio
87+
position: relative
88+
padding-top: 56.25% // 16:9 aspect ratio (9/16 = 0.5625)
89+
height: 0
90+
overflow: hidden
91+
92+
iframe
93+
position: absolute
94+
top: 0
95+
left: 0
96+
width: 100%
97+
height: 100%
98+
border: none
99+
100+
.big-text
101+
font-weight: bold
102+
font-size: 20px
103+
margin: 2px auto
104+
105+
.med-text
106+
font-size: 16px
107+
108+
.modal-text
109+
width: 90%
110+
margin: 0 auto
111+
hr
112+
border-top: 1px solid gray
113+
margin: 10px 40px
114+
115+
.actions
116+
display: flex
117+
justify-content: center
118+
margin-top: 10px
119+
120+
.play-button
121+
padding: 0 10px
122+
font-size: 24px
123+
line-height: 30px
124+
border-style: solid
125+
border-image: url(/images/common/button-background-success-active.png) 14 20 20 20 fill round
126+
&:hover
127+
border-image: url(/images/common/button-background-success-inactive.png) 14 20 20 20 fill round
128+
&:active
129+
border-image: url(/images/common/button-background-success-pressed.png) 14 20 20 20 fill round
130+
border-width: 14px 20px 20px 20px
131+
color: darken(white, 5%)

0 commit comments

Comments
 (0)