Skip to content

Commit

Permalink
Merge pull request #35152 from code-dot-org/dtl_candidate_24d77bd3
Browse files Browse the repository at this point in the history
  • Loading branch information
deploy-code-org committed Jun 4, 2020
2 parents 6ca05ea + 24d77bd commit 84f47f8
Show file tree
Hide file tree
Showing 24 changed files with 262 additions and 167 deletions.
2 changes: 1 addition & 1 deletion apps/src/applab/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -1159,7 +1159,7 @@ applabCommands.getImageURL = function(opts) {
return element.getAttribute('data-canonical-image-url');
} else if (
element.tagName === 'LABEL' &&
element.className === 'img-upload'
$(element).hasClass('img-upload')
) {
var fileObj = element.children[0].files[0];
if (fileObj) {
Expand Down
2 changes: 1 addition & 1 deletion apps/src/applab/designElements/photoSelect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export default {
onDeserialize: function(element, updateProperty) {
// Disable image upload events unless running
$(element).on('click', () => {
element.childNodes[0] = !Applab.isRunning();
element.childNodes[0].disabled = !Applab.isRunning();
});
}
};
2 changes: 1 addition & 1 deletion apps/src/code-studio/pd/foorm/FoormEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class FoormEditor extends React.Component {
type="text"
value={this.state.workshop_subject}
onChange={e =>
this.setState({workshop_course: e.target.value})
this.setState({workshop_subject: e.target.value})
}
/>
</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ const placeholderSession = {
endTime: '5:00pm'
};

// When selecting whether a workshop is virtual through the UI,
// a user is really selecting two things:
// a) whether the workshop is occurring virtually, and
// b) if there's a third party responsible for the content/structure of the workshop.
// These two things are stored as separate attributes in the workshop model.
const virtualWorkshopTypes = ['regional', 'friday_institute'];
const thirdPartyProviders = ['friday_institute'];

export class WorkshopForm extends React.Component {
static contextTypes = {
router: PropTypes.object.isRequired
Expand All @@ -78,7 +86,7 @@ export class WorkshopForm extends React.Component {
id: PropTypes.number.isRequired,
facilitators: PropTypes.array.isRequired,
location_name: PropTypes.string.isRequired,
location_address: PropTypes.string.isRequired,
location_address: PropTypes.string,
capacity: PropTypes.number.isRequired,
on_map: PropTypes.bool.isRequired,
funded: PropTypes.bool.isRequired,
Expand All @@ -92,6 +100,7 @@ export class WorkshopForm extends React.Component {
regional_partner_name: PropTypes.string,
regional_partner_id: PropTypes.number,
virtual: PropTypes.bool,
third_party_provider: PropTypes.string,
suppress_email: PropTypes.bool,
organizer: PropTypes.shape({
id: PropTypes.number,
Expand Down Expand Up @@ -131,7 +140,8 @@ export class WorkshopForm extends React.Component {
showTypeOptionsHelpDisplay: false,
regional_partner_id: '',
virtual: false,
suppress_email: false
suppress_email: false,
third_party_provider: null
};

if (props.workshop) {
Expand All @@ -152,7 +162,8 @@ export class WorkshopForm extends React.Component {
'regional_partner_id',
'organizer',
'virtual',
'suppress_email'
'suppress_email',
'third_party_provider'
])
);
initialState.sessions = this.prepareSessionsForForm(
Expand Down Expand Up @@ -737,13 +748,33 @@ export class WorkshopForm extends React.Component {
return value;
};

currentVirtualStatus = () => {
const {virtual, third_party_provider} = this.state;

// First, check if the third party provider is a valid
// virtual workshop type.
if (virtualWorkshopTypes.includes(third_party_provider)) {
return third_party_provider;
} else if (virtual) {
return 'regional';
} else {
return 'in_person';
}
};

handleVirtualChange = event => {
// This field gets its own handler both so we can coerce its value to
// boolean, and so we can enforce some business logic that says:
// Virtual workshops ALWAYS suppress email.
const virtual = event.target.value === 'true';
const value = event.target.value;
const virtual = virtualWorkshopTypes.includes(value);
const suppress_email = virtual || this.state.suppress_email;
this.setState({virtual, suppress_email});

this.setState({
virtual,
suppress_email,
third_party_provider: thirdPartyProviders.includes(value) ? value : null
});
};

handleSuppressEmailChange = event => {
Expand Down Expand Up @@ -812,6 +843,7 @@ export class WorkshopForm extends React.Component {
notes: this.state.notes,
virtual: this.state.virtual,
suppress_email: this.state.suppress_email,
third_party_provider: this.state.third_party_provider,
sessions_attributes: this.prepareSessionsForApi(
this.state.sessions,
this.state.destroyedSessions
Expand Down Expand Up @@ -1011,7 +1043,7 @@ export class WorkshopForm extends React.Component {
</HelpTip>
</ControlLabel>
<SelectIsVirtual
value={this.state.virtual || false}
value={this.currentVirtualStatus()}
onChange={this.handleVirtualChange}
readOnly={this.props.readOnly}
/>
Expand Down Expand Up @@ -1179,16 +1211,19 @@ const SelectIsVirtual = ({value, readOnly, onChange}) => (
style={readOnly ? styles.readOnlyInput : undefined}
disabled={readOnly}
>
<option key={false} value={false}>
<option key={'in_person'} value={'in_person'}>
No, this is an in-person workshop.
</option>
<option key={true} value={true}>
Yes, this is a virtual workshop.
<option key={'friday_institute'} value={'friday_institute'}>
Yes, this is a Code.org-Friday Institute virtual workshop.
</option>
<option key={'regional'} value={'regional'}>
Yes, this is a regional virtual workshop.
</option>
</FormControl>
);
SelectIsVirtual.propTypes = {
value: PropTypes.bool.isRequired,
value: PropTypes.string.isRequired,
readOnly: PropTypes.bool,
onChange: PropTypes.func.isRequired
};
Expand Down
3 changes: 2 additions & 1 deletion apps/src/code-studio/pd/workshop_dashboard/workshop.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ export class Workshop extends React.Component {
'potential_organizers',
'created_at',
'virtual',
'suppress_email'
'suppress_email',
'third_party_provider'
])
});
})
Expand Down
1 change: 1 addition & 0 deletions apps/src/p5lab/AnimationPicker/AnimationPicker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class AnimationPicker extends React.Component {
handleClose={this.props.onClose}
uncloseable={this.props.uploadInProgress}
fullWidth={true}
style={styles.dialog}
>
<HiddenUploader
ref="uploader"
Expand Down
10 changes: 10 additions & 0 deletions apps/src/p5lab/AnimationPicker/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
var color = require('@cdo/apps/util/color');

module.exports = {
dialog: {
/**
* Constrain the width of the dialog so that it is always vertically scrollable,
* which is necessary for infinite scroll to work.
* https://github.com/code-dot-org/code-dot-org/pull/34463
*/
maxWidth: 1000,
marginLeft: 0,
transform: 'translate(-50%, 0)'
},
title: {
color: color.purple,
textAlign: 'center',
Expand Down
1 change: 1 addition & 0 deletions apps/src/p5lab/spritelab/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module.exports.SpritelabReservedWords = [
'text',
'textAlign',
'textSize',
'setup',
// NativeSpriteLab.interpreted.js
'extraArgs',
'draw',
Expand Down
20 changes: 2 additions & 18 deletions apps/src/sites/code.org/pages/public/student/middle-high.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';

import MiddleHighResourceCards from './MiddleHighResourceCards';
import initResponsive from '@cdo/apps/code-studio/responsive';
import isRtl from '@cdo/apps/code-studio/isRtlRedux';
import responsive from '@cdo/apps/code-studio/responsiveRedux';
import {getStore, registerReducers} from '@cdo/apps/redux';

registerReducers({isRtl, responsive});

document.addEventListener('DOMContentLoaded', () => {
$(document).ready(function() {
initResponsive();

const container = document.getElementById('educate-resources-grid');
ReactDOM.render(
<Provider store={getStore()}>
<MiddleHighResourceCards />
</Provider>,
container
);
$('.hoc-tiles-container').load('/dashboardapi/middle_high_student_labs');
});
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ def workshop_params(can_update_regional_partner = true)
:organizer_id,
:virtual,
:suppress_email,
:third_party_provider,
sessions_attributes: [:id, :start, :end, :_destroy],
]

Expand Down
9 changes: 9 additions & 0 deletions dashboard/app/helpers/course_block_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ def self.get_tall_course_block(id, family_name = nil)
url: CDO.code_org_url('/educate/applab'),
body: I18n.t('upsell.applab.body_short')
},
'gamelab' => {
url: CDO.code_org_url('/educate/gamelab'),
body: I18n.t('upsell.gamelab.body')
},
'weblab' => {
url: CDO.code_org_url('/educate/weblab'),
title: "Web Lab",
body: I18n.t('upsell.weblab.body')
},
'conditionals' => {
url: CDO.code_org_url('/hourofcode/unplugged-conditionals-with-cards'),
title: I18n.t('upsell.unplugged_conditionals.title'),
Expand Down
16 changes: 16 additions & 0 deletions dashboard/app/models/pd/workshop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ class Pd::Workshop < ActiveRecord::Base
# - Uses a different, virtual-specific post-workshop survey.
'virtual',

# Allows a workshop to be associated with a third party
# organization.
# Only current allowed values are "friday_institute" and nil.
# "friday_institute" represents The Friday Institute,
# a regional partner whose model of virtual workshop is being used
# by several partners during summer 2020.
'third_party_provider',

# If true, our system will not send enrollee-facing
# emails related to this workshop *except* for a receipt for the teacher
# if they cancel their enrollment and the post-workshop survey,
Expand All @@ -84,6 +92,8 @@ class Pd::Workshop < ActiveRecord::Base
validates_inclusion_of :on_map, in: [true, false]
validates_inclusion_of :funded, in: [true, false]
validate :all_virtual_workshops_suppress_email
validates_inclusion_of :third_party_provider, in: %w(friday_institute), allow_nil: true
validate :friday_institute_workshops_must_be_virtual

validates :funding_type,
inclusion: {in: FUNDING_TYPES, if: :funded_csf?},
Expand Down Expand Up @@ -119,6 +129,12 @@ def all_virtual_workshops_suppress_email
end
end

def friday_institute_workshops_must_be_virtual
if third_party_provider == 'friday_institute' && !virtual?
errors.add :properties, 'Friday Institute workshops must be virtual'
end
end

def self.organized_by(organizer)
where(organizer_id: organizer.id)
end
Expand Down
2 changes: 1 addition & 1 deletion dashboard/app/serializers/api/v1/pd/workshop_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class Api::V1::Pd::WorkshopSerializer < ActiveModel::Serializer
:enrolled_teacher_count, :sessions, :account_required_for_attendance?,
:enrollment_code, :pre_workshop_survey_url, :attended, :on_map, :funded, :funding_type, :ready_to_close?,
:workshop_starting_date, :date_and_location_name, :regional_partner_name, :regional_partner_id,
:scholarship_workshop?, :can_delete, :created_at, :virtual, :suppress_email
:scholarship_workshop?, :can_delete, :created_at, :virtual, :suppress_email, :third_party_provider

def sessions
object.sessions.map do |session|
Expand Down
4 changes: 4 additions & 0 deletions dashboard/app/views/api/middle_high_student_labs.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.row{style: "margin: 0;"}
= render partial: 'shared/course_tall_block', locals: { id: 'applab' }
= render partial: 'shared/course_tall_block', locals: { id: 'gamelab' }
= render partial: 'shared/course_tall_block', locals: { id: 'weblab' }
17 changes: 17 additions & 0 deletions dashboard/test/models/pd/workshop_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,23 @@ class Pd::WorkshopTest < ActiveSupport::TestCase
assert workshop.valid?
end

test 'friday_institute workshops must be virtual' do
workshop = build :workshop, third_party_provider: 'friday_institute', virtual: false
refute workshop.valid?

workshop.virtual = true
workshop.suppress_email = true
assert workshop.valid?
end

test 'workshops third_party_provider must be nil or from specified list' do
workshop = build :workshop, third_party_provider: 'unknown_pd_provider'
refute workshop.valid?

workshop.third_party_provider = nil
assert workshop.valid?
end

private

def session_on_day(day_offset)
Expand Down

0 comments on commit 84f47f8

Please sign in to comment.