Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
badb1f84
Unverified
Commit
badb1f84
authored
Dec 12, 2017
by
Harry Rein
Committed by
GitHub
Dec 12, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #16783 from edx/HarryRein/course-run-selection-program-dashboard
Harry rein/course run selection program dashboard
parents
a9506c1a
2711fb52
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
310 additions
and
158 deletions
+310
-158
common/djangoapps/entitlements/models.py
+8
-0
lms/static/js/learner_dashboard/models/course_card_model.js
+18
-7
lms/static/js/learner_dashboard/models/course_entitlement_model.js
+1
-2
lms/static/js/learner_dashboard/views/course_card_view.js
+28
-1
lms/static/js/learner_dashboard/views/course_enroll_view.js
+1
-1
lms/static/js/learner_dashboard/views/course_entitlement_view.js
+57
-38
lms/static/js/learner_dashboard/views/program_details_view.js
+0
-1
lms/static/lms/js/spec/main.js
+6
-0
lms/static/sass/_build-learner-dashboard.scss
+3
-0
lms/static/sass/_build-lms-v1.scss
+3
-2
lms/static/sass/multicourse/_dashboard.scss
+1
-83
lms/static/sass/views/_course-entitlements.scss
+127
-0
lms/static/sass/views/_program-details.scss
+11
-3
lms/templates/dashboard.html
+4
-3
lms/templates/dashboard/_dashboard_course_listing.html
+1
-2
lms/templates/learner_dashboard/course_card.underscore
+8
-4
lms/templates/learner_dashboard/course_enroll.underscore
+1
-1
lms/templates/learner_dashboard/course_entitlement.underscore
+2
-2
lms/templates/learner_dashboard/program_details_fragment.html
+4
-0
openedx/core/djangoapps/programs/utils.py
+16
-5
themes/edx.org/lms/templates/dashboard.html
+4
-3
webpack.common.config.js
+6
-0
No files found.
common/djangoapps/entitlements/models.py
View file @
badb1f84
...
@@ -213,6 +213,14 @@ class CourseEntitlement(TimeStampedModel):
...
@@ -213,6 +213,14 @@ class CourseEntitlement(TimeStampedModel):
"""
"""
return
self
.
policy
.
is_entitlement_redeemable
(
self
)
return
self
.
policy
.
is_entitlement_redeemable
(
self
)
def
to_dict
(
self
):
""" Convert entitlement to dictionary representation. """
return
{
'uuid'
:
str
(
self
.
uuid
),
'course_uuid'
:
str
(
self
.
course_uuid
),
'expired_at'
:
self
.
expired_at
}
@classmethod
@classmethod
def
set_enrollment
(
cls
,
entitlement
,
enrollment
):
def
set_enrollment
(
cls
,
entitlement
,
enrollment
):
"""
"""
...
...
lms/static/js/learner_dashboard/models/course_card_model.js
View file @
badb1f84
...
@@ -42,6 +42,11 @@
...
@@ -42,6 +42,11 @@
return
desiredCourseRun
;
return
desiredCourseRun
;
},
},
isEnrolledInSession
:
function
()
{
// Returns true if the user is currently enrolled in a session of the course
return
_
.
findWhere
(
this
.
context
.
course_runs
,
{
is_enrolled
:
true
})
!==
undefined
;
},
getUnselectedCourseRun
:
function
(
courseRuns
)
{
getUnselectedCourseRun
:
function
(
courseRuns
)
{
var
unselectedRun
=
{},
var
unselectedRun
=
{},
courseRun
;
courseRun
;
...
@@ -143,8 +148,9 @@
...
@@ -143,8 +148,9 @@
formatDateString
:
function
(
run
)
{
formatDateString
:
function
(
run
)
{
var
pacingType
=
run
.
pacing_type
,
var
pacingType
=
run
.
pacing_type
,
dateString
,
dateString
,
start
=
this
.
get
(
'start_date'
)
||
run
.
start_date
,
start
=
this
.
valueIsDefined
(
run
.
start_date
)
?
run
.
advertised_start
||
run
.
start_date
:
end
=
this
.
get
(
'end_date'
)
||
run
.
end_date
,
this
.
get
(
'start_date'
),
end
=
this
.
valueIsDefined
(
run
.
end_date
)
?
run
.
end_date
:
this
.
get
(
'end_date'
),
now
=
new
Date
(),
now
=
new
Date
(),
startDate
=
new
Date
(
start
),
startDate
=
new
Date
(
start
),
endDate
=
new
Date
(
end
);
endDate
=
new
Date
(
end
);
...
@@ -178,26 +184,27 @@
...
@@ -178,26 +184,27 @@
},
},
setActiveCourseRun
:
function
(
courseRun
,
userPreferences
)
{
setActiveCourseRun
:
function
(
courseRun
,
userPreferences
)
{
var
startDateString
;
var
startDateString
,
isEnrolled
=
this
.
isEnrolledInSession
()
&&
courseRun
.
key
;
if
(
courseRun
)
{
if
(
courseRun
)
{
if
(
this
.
valueIsDefined
(
courseRun
.
advertised_start
))
{
if
(
this
.
valueIsDefined
(
courseRun
.
advertised_start
))
{
startDateString
=
courseRun
.
advertised_start
;
startDateString
=
courseRun
.
advertised_start
;
}
else
{
}
else
{
startDateString
=
this
.
formatDate
(
courseRun
.
start
,
userPreferences
);
startDateString
=
this
.
formatDate
(
courseRun
.
start
,
userPreferences
);
}
}
this
.
set
({
this
.
set
({
certificate_url
:
courseRun
.
certificate_url
,
certificate_url
:
courseRun
.
certificate_url
,
course_run_key
:
courseRun
.
key
,
course_run_key
:
courseRun
.
key
||
''
,
course_url
:
courseRun
.
course_url
||
''
,
course_url
:
courseRun
.
course_url
||
''
,
title
:
this
.
context
.
title
,
title
:
this
.
context
.
title
,
end_date
:
this
.
formatDate
(
courseRun
.
end
,
userPreferences
),
end_date
:
this
.
formatDate
(
courseRun
.
end
,
userPreferences
),
enrollable_course_runs
:
this
.
getEnrollableCourseRuns
(),
enrollable_course_runs
:
this
.
getEnrollableCourseRuns
(),
is_course_ended
:
courseRun
.
is_course_ended
,
is_course_ended
:
courseRun
.
is_course_ended
,
is_enrolled
:
courseRun
.
is_e
nrolled
,
is_enrolled
:
isE
nrolled
,
is_enrollment_open
:
courseRun
.
is_enrollment_open
,
is_enrollment_open
:
courseRun
.
is_enrollment_open
,
course_key
:
this
.
context
.
key
,
course_key
:
this
.
context
.
key
,
user_entitlement
:
this
.
context
.
user_entitlement
,
is_unfulfilled_entitlement
:
this
.
context
.
user_entitlement
&&
!
isEnrolled
,
marketing_url
:
courseRun
.
marketing_url
,
marketing_url
:
courseRun
.
marketing_url
,
mode_slug
:
courseRun
.
type
,
mode_slug
:
courseRun
.
type
,
start_date
:
startDateString
,
start_date
:
startDateString
,
...
@@ -220,6 +227,10 @@
...
@@ -220,6 +227,10 @@
updateCourseRun
:
function
(
courseRunKey
)
{
updateCourseRun
:
function
(
courseRunKey
)
{
var
selectedCourseRun
=
_
.
findWhere
(
this
.
get
(
'course_runs'
),
{
key
:
courseRunKey
});
var
selectedCourseRun
=
_
.
findWhere
(
this
.
get
(
'course_runs'
),
{
key
:
courseRunKey
});
if
(
selectedCourseRun
)
{
if
(
selectedCourseRun
)
{
// Update the current context to set the course run to the enrolled state
_
.
each
(
this
.
context
.
course_runs
,
function
(
run
)
{
if
(
run
.
key
===
selectedCourseRun
.
key
)
run
.
is_enrolled
=
true
;
// eslint-disable-line no-param-reassign, max-len
});
this
.
setActiveCourseRun
(
selectedCourseRun
);
this
.
setActiveCourseRun
(
selectedCourseRun
);
}
}
}
}
...
...
lms/static/js/learner_dashboard/models/course_entitlement_model.js
View file @
badb1f84
/**
/**
* Store data for the current
* Store data for the current
entitlement.
*/
*/
(
function
(
define
)
{
(
function
(
define
)
{
'use strict'
;
'use strict'
;
...
@@ -13,7 +13,6 @@
...
@@ -13,7 +13,6 @@
availableSessions
:
[],
availableSessions
:
[],
entitlementUUID
:
''
,
entitlementUUID
:
''
,
currentSessionId
:
''
,
currentSessionId
:
''
,
userId
:
''
,
courseName
:
''
courseName
:
''
}
}
});
});
...
...
lms/static/js/learner_dashboard/views/course_card_view.js
View file @
badb1f84
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
'js/learner_dashboard/views/certificate_status_view'
,
'js/learner_dashboard/views/certificate_status_view'
,
'js/learner_dashboard/views/expired_notification_view'
,
'js/learner_dashboard/views/expired_notification_view'
,
'js/learner_dashboard/views/course_enroll_view'
,
'js/learner_dashboard/views/course_enroll_view'
,
'js/learner_dashboard/views/course_entitlement_view'
,
'text!../../../templates/learner_dashboard/course_card.underscore'
'text!../../../templates/learner_dashboard/course_card.underscore'
],
],
function
(
function
(
...
@@ -24,6 +25,7 @@
...
@@ -24,6 +25,7 @@
CertificateStatusView
,
CertificateStatusView
,
ExpiredNotificationView
,
ExpiredNotificationView
,
CourseEnrollView
,
CourseEnrollView
,
EntitlementView
,
pageTpl
pageTpl
)
{
)
{
return
Backbone
.
View
.
extend
({
return
Backbone
.
View
.
extend
({
...
@@ -41,6 +43,8 @@
...
@@ -41,6 +43,8 @@
this
.
grade
=
this
.
context
.
courseData
.
grades
[
this
.
model
.
get
(
'course_run_key'
)];
this
.
grade
=
this
.
context
.
courseData
.
grades
[
this
.
model
.
get
(
'course_run_key'
)];
this
.
grade
=
this
.
grade
*
100
;
this
.
grade
=
this
.
grade
*
100
;
this
.
collectionCourseStatus
=
this
.
context
.
collectionCourseStatus
||
''
;
this
.
collectionCourseStatus
=
this
.
context
.
collectionCourseStatus
||
''
;
this
.
entitlement
=
this
.
model
.
get
(
'user_entitlement'
);
this
.
render
();
this
.
render
();
this
.
listenTo
(
this
.
model
,
'change'
,
this
.
render
);
this
.
listenTo
(
this
.
model
,
'change'
,
this
.
render
);
},
},
...
@@ -57,7 +61,9 @@
...
@@ -57,7 +61,9 @@
var
$upgradeMessage
=
this
.
$
(
'.upgrade-message'
),
var
$upgradeMessage
=
this
.
$
(
'.upgrade-message'
),
$certStatus
=
this
.
$
(
'.certificate-status'
),
$certStatus
=
this
.
$
(
'.certificate-status'
),
$expiredNotification
=
this
.
$
(
'.expired-notification'
),
$expiredNotification
=
this
.
$
(
'.expired-notification'
),
expired
=
this
.
model
.
get
(
'expired'
);
expired
=
this
.
model
.
get
(
'expired'
),
courseUUID
=
this
.
model
.
get
(
'uuid'
),
containerSelector
=
'#course-'
+
courseUUID
;
this
.
enrollView
=
new
CourseEnrollView
({
this
.
enrollView
=
new
CourseEnrollView
({
$parentEl
:
this
.
$
(
'.course-actions'
),
$parentEl
:
this
.
$
(
'.course-actions'
),
...
@@ -68,6 +74,27 @@
...
@@ -68,6 +74,27 @@
enrollModel
:
this
.
enrollModel
enrollModel
:
this
.
enrollModel
});
});
if
(
this
.
entitlement
)
{
this
.
sessionSelectionView
=
new
EntitlementView
({
el
:
this
.
$
(
containerSelector
+
' .course-entitlement-selection-container'
),
$parentEl
:
this
.
$el
,
courseCardModel
:
this
.
model
,
enrollModel
:
this
.
enrollModel
,
triggerOpenBtn
:
'.course-details .change-session'
,
courseCardMessages
:
''
,
courseImageLink
:
''
,
courseTitleLink
:
containerSelector
+
' .course-details .course-title'
,
dateDisplayField
:
containerSelector
+
' .course-details .course-text'
,
enterCourseBtn
:
containerSelector
+
' .view-course-button'
,
availableSessions
:
JSON
.
stringify
(
this
.
model
.
get
(
'course_runs'
)),
entitlementUUID
:
this
.
entitlement
.
uuid
,
currentSessionId
:
this
.
model
.
isEnrolledInSession
()
?
this
.
model
.
get
(
'course_run_key'
)
:
null
,
enrollUrl
:
this
.
model
.
get
(
'enroll_url'
),
courseHomeUrl
:
this
.
model
.
get
(
'course_url'
)
});
}
if
(
this
.
model
.
get
(
'upgrade_url'
)
&&
!
(
expired
===
true
))
{
if
(
this
.
model
.
get
(
'upgrade_url'
)
&&
!
(
expired
===
true
))
{
this
.
upgradeMessage
=
new
UpgradeMessageView
({
this
.
upgradeMessage
=
new
UpgradeMessageView
({
$el
:
$upgradeMessage
,
$el
:
$upgradeMessage
,
...
...
lms/static/js/learner_dashboard/views/course_enroll_view.js
View file @
badb1f84
...
@@ -57,7 +57,7 @@
...
@@ -57,7 +57,7 @@
// Enrollment click event handled here
// Enrollment click event handled here
var
courseRunKey
=
$
(
'.run-select'
).
val
()
||
this
.
model
.
get
(
'course_run_key'
);
var
courseRunKey
=
$
(
'.run-select'
).
val
()
||
this
.
model
.
get
(
'course_run_key'
);
this
.
model
.
updateCourseRun
(
courseRunKey
);
this
.
model
.
updateCourseRun
(
courseRunKey
);
if
(
!
this
.
model
.
get
(
'is_enrolled'
))
{
if
(
this
.
model
.
get
(
'is_enrolled'
))
{
// Create the enrollment.
// Create the enrollment.
this
.
enrollModel
.
save
({
this
.
enrollModel
.
save
({
course_id
:
courseRunKey
course_id
:
courseRunKey
...
...
lms/static/js/learner_dashboard/views/course_entitlement_view.js
View file @
badb1f84
...
@@ -37,12 +37,12 @@
...
@@ -37,12 +37,12 @@
initialize
:
function
(
options
)
{
initialize
:
function
(
options
)
{
// Set up models and reload view on change
// Set up models and reload view on change
this
.
courseCardModel
=
new
CourseCardModel
();
this
.
courseCardModel
=
options
.
courseCardModel
||
new
CourseCardModel
();
this
.
enrollModel
=
options
.
enrollModel
;
this
.
entitlementModel
=
new
EntitlementModel
({
this
.
entitlementModel
=
new
EntitlementModel
({
availableSessions
:
this
.
formatDates
(
JSON
.
parse
(
options
.
availableSessions
)),
availableSessions
:
this
.
formatDates
(
JSON
.
parse
(
options
.
availableSessions
)),
entitlementUUID
:
options
.
entitlementUUID
,
entitlementUUID
:
options
.
entitlementUUID
,
currentSessionId
:
options
.
currentSessionId
,
currentSessionId
:
options
.
currentSessionId
,
userId
:
options
.
userId
,
courseName
:
options
.
courseName
courseName
:
options
.
courseName
});
});
this
.
listenTo
(
this
.
entitlementModel
,
'change'
,
this
.
render
);
this
.
listenTo
(
this
.
entitlementModel
,
'change'
,
this
.
render
);
...
@@ -51,13 +51,18 @@
...
@@ -51,13 +51,18 @@
this
.
enrollUrl
=
options
.
enrollUrl
;
this
.
enrollUrl
=
options
.
enrollUrl
;
this
.
courseHomeUrl
=
options
.
courseHomeUrl
;
this
.
courseHomeUrl
=
options
.
courseHomeUrl
;
// Grab elements from the parent card that work with this view and bind associated events
// Grab elements from the parent card that work with this view
this
.
$triggerOpenBtn
=
$
(
options
.
triggerOpenBtn
);
// Opens/closes session selection view
this
.
$parentEl
=
options
.
$parentEl
;
// Containing course card (must be a backbone view root el)
this
.
$dateDisplayField
=
$
(
options
.
dateDisplayField
);
// Displays current session dates
this
.
$enterCourseBtn
=
$
(
options
.
enterCourseBtn
);
// Button link to course home page
this
.
$enterCourseBtn
=
$
(
options
.
enterCourseBtn
);
// Button link to course home page
this
.
$courseCardMessages
=
$
(
options
.
courseCardMessages
);
// Additional session messages
this
.
$courseCardMessages
=
$
(
options
.
courseCardMessages
);
// Additional session messages
this
.
$courseTitleLink
=
$
(
options
.
courseTitleLink
);
// Title link to course home page
this
.
$courseTitleLink
=
$
(
options
.
courseTitleLink
);
// Title link to course home page
this
.
$courseImageLink
=
$
(
options
.
courseImageLink
);
// Image link to course home page
this
.
$courseImageLink
=
$
(
options
.
courseImageLink
);
// Image link to course home page
// Bind action elements with associated events to objects outside this view
this
.
$dateDisplayField
=
this
.
$parentEl
?
this
.
$parentEl
.
find
(
options
.
dateDisplayField
)
:
$
(
options
.
dateDisplayField
);
// Displays current session dates
this
.
$triggerOpenBtn
=
this
.
$parentEl
?
this
.
$parentEl
.
find
(
options
.
triggerOpenBtn
)
:
$
(
options
.
triggerOpenBtn
);
// Opens/closes session selection view
this
.
$triggerOpenBtn
.
on
(
'click'
,
this
.
toggleSessionSelectionPanel
.
bind
(
this
));
this
.
$triggerOpenBtn
.
on
(
'click'
,
this
.
toggleSessionSelectionPanel
.
bind
(
this
));
this
.
render
(
options
);
this
.
render
(
options
);
...
@@ -72,15 +77,17 @@
...
@@ -72,15 +77,17 @@
},
},
postRender
:
function
()
{
postRender
:
function
()
{
// Close
popover
on click-away
// Close
any visible popovers
on click-away
$
(
document
).
on
(
'click'
,
function
(
e
)
{
$
(
document
).
on
(
'click'
,
function
(
e
)
{
if
(
!
(
$
(
e
.
target
).
closest
(
'.enroll-btn-initial, .popover'
).
length
))
{
if
(
this
.
$
(
'.popover:visible'
).
length
&&
!
(
$
(
e
.
target
).
closest
(
'.enroll-btn-initial, .popover'
).
length
))
{
this
.
hideDialog
(
this
.
$
(
'.enroll-btn-initial'
));
this
.
hideDialog
(
this
.
$
(
'.enroll-btn-initial'
));
}
}
}.
bind
(
this
));
}.
bind
(
this
));
this
.
$
(
'.enroll-btn-initial'
).
click
(
function
(
e
)
{
// Initialize focus to cancel button on popover load
this
.
showDialog
(
$
(
e
.
target
));
$
(
document
).
on
(
'shown.bs.popover'
,
function
()
{
this
.
$
(
'.final-confirmation-btn:first'
).
focus
();
}.
bind
(
this
));
}.
bind
(
this
));
},
},
...
@@ -130,7 +137,13 @@
...
@@ -130,7 +137,13 @@
*/
*/
var
successIconEl
=
'<span class="fa fa-check" aria-hidden="true"></span>'
;
var
successIconEl
=
'<span class="fa fa-check" aria-hidden="true"></span>'
;
// Update the model with the new session Id;
// With a containing backbone view, we can simply re-render the parent card
if
(
this
.
$parentEl
)
{
this
.
courseCardModel
.
updateCourseRun
(
this
.
currentSessionSelection
);
return
;
}
// Update the model with the new session Id
this
.
entitlementModel
.
set
({
currentSessionId
:
this
.
currentSessionSelection
});
this
.
entitlementModel
.
set
({
currentSessionId
:
this
.
currentSessionSelection
});
// Allow user to change session
// Allow user to change session
...
@@ -161,6 +174,11 @@
...
@@ -161,6 +174,11 @@
3) Remove the messages associated with the enrolled state.
3) Remove the messages associated with the enrolled state.
4) Remove the link from the course card image and title.
4) Remove the link from the course card image and title.
*/
*/
// With a containing backbone view, we can simply re-render the parent card
if
(
this
.
$parentEl
)
{
this
.
courseCardModel
.
setUnselected
();
return
;
}
// Update the model with the new session Id;
// Update the model with the new session Id;
this
.
entitlementModel
.
set
({
currentSessionId
:
this
.
currentSessionSelection
});
this
.
entitlementModel
.
set
({
currentSessionId
:
this
.
currentSessionSelection
});
...
@@ -198,13 +216,18 @@
...
@@ -198,13 +216,18 @@
},
},
enrollError
:
function
()
{
enrollError
:
function
()
{
var
errorMsgEl
=
HtmlUtils
.
HTML
(
// Display a success indicator
gettext
(
'There was an error. Please reload the page and try again.'
)
var
errorMsgEl
=
HtmlUtils
.
joinHtml
(
HtmlUtils
.
HTML
(
'<span class="enroll-error">'
),
gettext
(
'There was an error. Please reload the page and try again.'
),
HtmlUtils
.
HTML
(
'</spandiv>'
)
).
text
;
).
text
;
this
.
$dateDisplayField
this
.
$dateDisplayField
.
find
(
'.fa.fa-spin'
)
.
find
(
'.fa.fa-spin'
)
.
removeClass
(
'fa-spin fa-spinner'
)
.
removeClass
(
'fa-spin fa-spinner'
)
.
addClass
(
'fa-close'
);
.
addClass
(
'fa-close'
);
this
.
$dateDisplayField
.
append
(
errorMsgEl
);
this
.
$dateDisplayField
.
append
(
errorMsgEl
);
this
.
hideDialog
(
this
.
$
(
'.enroll-btn-initial'
));
this
.
hideDialog
(
this
.
$
(
'.enroll-btn-initial'
));
},
},
...
@@ -237,7 +260,6 @@
...
@@ -237,7 +260,6 @@
enrollText
=
gettext
(
'Leave Current Session'
);
enrollText
=
gettext
(
'Leave Current Session'
);
}
}
enrollBtnInitial
.
text
(
enrollText
);
enrollBtnInitial
.
text
(
enrollText
);
this
.
removeDialog
(
enrollBtnInitial
);
this
.
initializeVerificationDialog
(
enrollBtnInitial
);
this
.
initializeVerificationDialog
(
enrollBtnInitial
);
},
},
...
@@ -263,7 +285,6 @@
...
@@ -263,7 +285,6 @@
*/
*/
var
confirmationMsgTitle
,
var
confirmationMsgTitle
,
confirmationMsgBody
,
confirmationMsgBody
,
popoverDialogHtml
,
currentSessionId
=
this
.
entitlementModel
.
get
(
'currentSessionId'
),
currentSessionId
=
this
.
entitlementModel
.
get
(
'currentSessionId'
),
newSessionId
=
this
.
$
(
'.session-select'
).
find
(
'option:selected'
).
data
(
'session_id'
);
newSessionId
=
this
.
$
(
'.session-select'
).
find
(
'option:selected'
).
data
(
'session_id'
);
...
@@ -279,38 +300,35 @@
...
@@ -279,38 +300,35 @@
confirmationMsgBody
=
gettext
(
'Any course progress or grades from your current session will be lost.'
);
// eslint-disable-line max-len
confirmationMsgBody
=
gettext
(
'Any course progress or grades from your current session will be lost.'
);
// eslint-disable-line max-len
}
}
// Remove existing popover and re-initialize
// Re-initialize the popover
popoverDialogHtml
=
this
.
verificationTpl
({
confirmationMsgTitle
:
confirmationMsgTitle
,
confirmationMsgBody
:
confirmationMsgBody
});
invokingElement
.
popover
({
invokingElement
.
popover
({
placement
:
'bottom'
,
placement
:
'bottom'
,
container
:
this
.
$el
,
container
:
this
.
$el
,
html
:
true
,
html
:
true
,
trigger
:
'click'
,
trigger
:
'click'
,
content
:
popoverDialogHtml
.
text
content
:
this
.
verificationTpl
({
confirmationMsgTitle
:
confirmationMsgTitle
,
confirmationMsgBody
:
confirmationMsgBody
}).
text
});
});
},
},
removeDialog
:
function
(
invokingElement
)
{
removeDialog
:
function
(
el
)
{
/* Removes the Bootstrap v4 dialog modal from the update session enrollment button. */
/* Removes the Bootstrap v4 dialog modal from the update session enrollment button. */
invokingElement
.
popover
(
'dispose'
);
var
$el
=
el
instanceof
jQuery
?
el
:
this
.
$
(
'.enroll-btn-initial'
);
},
if
(
this
.
$
(
'popover'
).
length
)
{
$el
.
popover
(
'dispose'
);
showDialog
:
function
(
invokingElement
)
{
}
/* Given an element with an associated dialog modal, shows the modal. */
invokingElement
.
popover
(
'show'
);
this
.
$
(
'.final-confirmation-btn:first'
).
focus
();
},
},
hideDialog
:
function
(
el
,
returnFocus
)
{
hideDialog
:
function
(
el
,
returnFocus
)
{
/* Hides the
modal
without removing it from the DOM. */
/* Hides the
modal if it is visible
without removing it from the DOM. */
var
$el
=
el
instanceof
jQuery
?
el
:
this
.
$
(
'.enroll-btn-initial'
);
var
$el
=
el
instanceof
jQuery
?
el
:
this
.
$
(
'.enroll-btn-initial'
);
$el
.
popover
(
'hide'
);
if
(
this
.
$
(
'.popover:visible'
).
length
)
{
if
(
returnFocus
)
{
$el
.
popover
(
'hide'
);
$el
.
focus
();
if
(
returnFocus
)
{
$el
.
focus
();
}
}
}
},
},
...
@@ -363,12 +381,13 @@
...
@@ -363,12 +381,13 @@
return
_
.
map
(
formattedSessionData
,
function
(
session
)
{
return
_
.
map
(
formattedSessionData
,
function
(
session
)
{
var
formattedSession
=
session
;
var
formattedSession
=
session
;
startDate
=
this
.
formatDate
(
formattedSession
.
s
ession_s
tart
,
dateFormat
);
startDate
=
this
.
formatDate
(
formattedSession
.
start
,
dateFormat
);
endDate
=
this
.
formatDate
(
formattedSession
.
session_
end
,
dateFormat
);
endDate
=
this
.
formatDate
(
formattedSession
.
end
,
dateFormat
);
formattedSession
.
enrollment_end
=
this
.
formatDate
(
formattedSession
.
enrollment_end
,
dateFormat
);
formattedSession
.
enrollment_end
=
this
.
formatDate
(
formattedSession
.
enrollment_end
,
dateFormat
);
formattedSession
.
session_dates
=
this
.
courseCardModel
.
formatDateString
({
formattedSession
.
session_dates
=
this
.
courseCardModel
.
formatDateString
({
start_date
:
session
.
session_start_advertised
||
startDate
,
start_date
:
startDate
,
end_date
:
session
.
session_start_advertised
?
null
:
endDate
,
advertised_start
:
session
.
advertised_start
,
end_date
:
endDate
,
pacing_type
:
formattedSession
.
pacing_type
pacing_type
:
formattedSession
.
pacing_type
});
});
return
formattedSession
;
return
formattedSession
;
...
@@ -376,7 +395,7 @@
...
@@ -376,7 +395,7 @@
},
},
formatDate
:
function
(
date
,
dateFormat
)
{
formatDate
:
function
(
date
,
dateFormat
)
{
return
date
?
moment
((
new
Date
(
date
))).
format
(
dateFormat
)
:
null
;
return
date
?
moment
((
new
Date
(
date
))).
format
(
dateFormat
)
:
''
;
},
},
getAvailableSessionWithId
:
function
(
sessionId
)
{
getAvailableSessionWithId
:
function
(
sessionId
)
{
...
...
lms/static/js/learner_dashboard/views/program_details_view.js
View file @
badb1f84
...
@@ -36,7 +36,6 @@
...
@@ -36,7 +36,6 @@
initialize
:
function
(
options
)
{
initialize
:
function
(
options
)
{
this
.
options
=
options
;
this
.
options
=
options
;
this
.
programModel
=
new
Backbone
.
Model
(
this
.
options
.
programData
);
this
.
programModel
=
new
Backbone
.
Model
(
this
.
options
.
programData
);
this
.
courseData
=
new
Backbone
.
Model
(
this
.
options
.
courseData
);
this
.
courseData
=
new
Backbone
.
Model
(
this
.
options
.
courseData
);
this
.
certificateCollection
=
new
Backbone
.
Collection
(
this
.
options
.
certificateData
);
this
.
certificateCollection
=
new
Backbone
.
Collection
(
this
.
options
.
certificateData
);
...
...
lms/static/lms/js/spec/main.js
View file @
badb1f84
...
@@ -46,6 +46,8 @@
...
@@ -46,6 +46,8 @@
'backbone.associations'
:
'xmodule_js/common_static/js/vendor/backbone-associations-min'
,
'backbone.associations'
:
'xmodule_js/common_static/js/vendor/backbone-associations-min'
,
'backbone.paginator'
:
'common/js/vendor/backbone.paginator'
,
'backbone.paginator'
:
'common/js/vendor/backbone.paginator'
,
'backbone-super'
:
'js/vendor/backbone-super'
,
'backbone-super'
:
'js/vendor/backbone-super'
,
'popper'
:
'common/js/vendor/popper'
,
'bootstrap'
:
'common/js/vendor/bootstrap'
,
'URI'
:
'xmodule_js/common_static/js/vendor/URI.min'
,
'URI'
:
'xmodule_js/common_static/js/vendor/URI.min'
,
'tinymce'
:
'xmodule_js/common_static/js/vendor/tinymce/js/tinymce/tinymce.full.min'
,
'tinymce'
:
'xmodule_js/common_static/js/vendor/tinymce/js/tinymce/tinymce.full.min'
,
'jquery.tinymce'
:
'xmodule_js/common_static/js/vendor/tinymce/js/tinymce/jquery.tinymce'
,
'jquery.tinymce'
:
'xmodule_js/common_static/js/vendor/tinymce/js/tinymce/jquery.tinymce'
,
...
@@ -197,6 +199,10 @@
...
@@ -197,6 +199,10 @@
'backbone-super'
:
{
'backbone-super'
:
{
deps
:
[
'backbone'
]
deps
:
[
'backbone'
]
},
},
'bootstrap'
:
{
deps
:
[
'jquery'
,
'popper'
],
exports
:
'bootstrap'
},
'paging-collection'
:
{
'paging-collection'
:
{
deps
:
[
'jquery'
,
'underscore'
,
'backbone.paginator'
]
deps
:
[
'jquery'
,
'underscore'
,
'backbone.paginator'
]
},
},
...
...
lms/static/sass/_build-learner-dashboard.scss
View file @
badb1f84
...
@@ -10,5 +10,8 @@
...
@@ -10,5 +10,8 @@
@import
'elements/program-card'
;
@import
'elements/program-card'
;
@import
'elements-v2/icons'
;
@import
'elements-v2/icons'
;
@import
'elements/progress-circle'
;
@import
'elements/progress-circle'
;
// Various View Styling
@import
'views/course-entitlements'
;
@import
'views/program-details'
;
@import
'views/program-details'
;
@import
'views/program-list'
;
@import
'views/program-list'
;
lms/static/sass/_build-lms-v1.scss
View file @
badb1f84
...
@@ -51,7 +51,8 @@
...
@@ -51,7 +51,8 @@
@import
'multicourse/survey-page'
;
@import
'multicourse/survey-page'
;
// base - specific views
// base - specific views
@import
"views/account-settings"
;
@import
'views/account-settings'
;
@import
'views/course-entitlements'
;
@import
'views/login-register'
;
@import
'views/login-register'
;
@import
'views/verification'
;
@import
'views/verification'
;
@import
'views/decoupled-verification'
;
@import
'views/decoupled-verification'
;
...
@@ -59,7 +60,7 @@
...
@@ -59,7 +60,7 @@
@import
'views/homepage'
;
@import
'views/homepage'
;
@import
'views/support'
;
@import
'views/support'
;
@import
'views/oauth2'
;
@import
'views/oauth2'
;
@import
"views/financial-assistance"
;
@import
'views/financial-assistance'
;
@import
'course/auto-cert'
;
@import
'course/auto-cert'
;
@import
'views/api-access'
;
@import
'views/api-access'
;
...
...
lms/static/sass/multicourse/_dashboard.scss
View file @
badb1f84
...
@@ -1045,6 +1045,7 @@
...
@@ -1045,6 +1045,7 @@
.related-programs-preface
{
.related-programs-preface
{
@include
float
(
left
);
@include
float
(
left
);
margin
:
0
$baseline
/
2
;
font-weight
:
bold
;
font-weight
:
bold
;
}
}
...
@@ -1095,89 +1096,6 @@
...
@@ -1095,89 +1096,6 @@
@include
padding
(
$baseline
/
2
,
$baseline
,
$baseline
/
2
,
$baseline
/
2
);
@include
padding
(
$baseline
/
2
,
$baseline
,
$baseline
/
2
,
$baseline
/
2
);
}
}
}
}
// Course Entitlement Session Selection
.course-entitlement-selection-container
{
background-color
:
theme-color
(
"inverse"
);
.action-header
{
padding-bottom
:
$baseline
/
4
;
font-weight
:
$font-weight-bold
;
color
:
theme-color
(
"dark"
);
}
.action-controls
{
display
:
flex
;
.session-select
{
background-color
:
theme-color
(
"inverse"
);
height
:
$baseline
*
1
.5
;
flex-grow
:
5
;
margin-bottom
:
$baseline
*
0
.4
;
}
.enroll-btn-initial
{
@include
margin-left
(
$baseline
);
height
:
$baseline
*
1
.5
;
flex-grow
:
1
;
letter-spacing
:
0
;
background
:
theme-color
(
"inverse"
);
border-color
:
theme-color
(
"primary"
);
color
:
theme-color
(
"primary"
);
text-shadow
:
none
;
font-size
:
$font-size-base
;
padding
:
0
;
box-shadow
:
none
;
border-radius
:
$border-radius-sm
;
transition
:
all
0
.4s
ease-out
;
&
:hover
{
background
:
theme-color
(
"primary"
);
border-color
:
theme-color
(
"primary"
);
color
:
theme-color
(
"inverse"
);
}
}
@include
media-breakpoint-down
(
xs
)
{
flex-direction
:
column
;
.enroll-btn-initial
{
margin
:
$baseline
/
4
0
$baseline
/
4
;
}
}
}
.popover
{
.popover-title
{
margin-bottom
:
$baseline
/
2
;
}
.action-items
{
display
:
flex
;
justify-content
:
space-between
;
margin-top
:
$baseline
/
2
;
.final-confirmation-btn
{
box-shadow
:
none
;
border
:
1px
solid
theme-color
(
"dark"
);
background
:
none
;
color
:
theme-color
(
"dark"
);
text-shadow
:
none
;
letter-spacing
:
0
;
flex-grow
:
1
;
margin
:
0
$baseline
/
4
;
padding
:
$baseline
/
10
$baseline
;
font-size
:
$font-size-base
;
&
:hover
{
background
:
theme-color
(
"primary"
);
color
:
theme-color
(
"inverse"
);
}
}
}
}
}
}
}
// CASE: empty dashboard
// CASE: empty dashboard
...
...
lms/static/sass/views/_course-entitlements.scss
0 → 100644
View file @
badb1f84
// Shared styling between courses and programs dashboard
.course-entitlement-selection-container
{
width
:
100%
;
position
:
relative
;
flex-grow
:
1
;
.action-header
{
padding-bottom
:
$baseline
/
4
;
font-weight
:
$font-weight-bold
;
color
:
theme-color
(
"dark"
);
}
.action-controls
{
display
:
flex
;
.session-select
{
background-color
:
theme-color
(
"inverse"
);
height
:
$baseline
*
1
.5
;
flex-grow
:
5
;
margin-bottom
:
$baseline
*
0
.4
;
max-width
:
calc
(
100%
-
200px
);
}
.enroll-btn-initial
{
@include
margin-left
(
$baseline
);
height
:
$baseline
*
1
.5
;
flex-grow
:
1
;
letter-spacing
:
0
;
background
:
theme-color
(
"inverse"
);
border-color
:
theme-color
(
"primary"
);
color
:
theme-color
(
"primary"
);
text-shadow
:
none
;
font-size
:
$font-size-base
;
padding
:
0
;
box-shadow
:
none
;
border-radius
:
$border-radius-sm
;
transition
:
all
0
.4s
ease-out
;
&
:hover
{
background
:
theme-color
(
"primary"
);
border-color
:
theme-color
(
"primary"
);
color
:
theme-color
(
"inverse"
);
}
&
.disabled
{
pointer-events
:
none
;
opacity
:
0
.5
;
}
}
@include
media-breakpoint-down
(
xs
)
{
flex-direction
:
column
;
.session-select
{
max-width
:
100%
;
}
.enroll-btn-initial
{
margin
:
$baseline
/
4
0
;
}
}
}
.popover
{
.popover-title
{
margin-bottom
:
$baseline
/
2
;
}
.action-items
{
display
:
flex
;
justify-content
:
space-between
;
margin-top
:
$baseline
/
2
;
.final-confirmation-btn
{
box-shadow
:
none
;
border
:
1px
solid
theme-color
(
"dark"
);
background
:
none
;
color
:
theme-color
(
"dark"
);
text-shadow
:
none
;
letter-spacing
:
0
;
flex-grow
:
1
;
margin
:
0
$baseline
/
4
;
padding
:
$baseline
/
10
$baseline
;
font-size
:
$font-size-base
;
&
:hover
{
background
:
theme-color
(
"primary"
);
color
:
theme-color
(
"inverse"
);
}
}
}
}
}
// Styling overrides specific to the programs dashboard
.program-course-card
{
.course-text
{
.fa-close
{
color
:
theme-color
(
"error"
);
}
.enroll-error
{
@include
margin-left
(
$baseline
/
4
);
font-size
:
$font-size-sm
;
}
.change-session
{
@include
margin
(
0
,
0
,
$baseline
/
4
,
$baseline
/
4
);
padding
:
0
;
font-size
:
$font-size-sm
;
letter-spacing
:
normal
;
}
}
.course-entitlement-selection-container
{
padding-top
:
$baseline
/
2
;
.action-header
,
.action-controls
.session-select
{
font-size
:
$font-size-sm
;
}
}
}
lms/static/sass/views/_program-details.scss
View file @
badb1f84
...
@@ -437,7 +437,6 @@
...
@@ -437,7 +437,6 @@
.program-course-card
{
.program-course-card
{
width
:
100%
;
width
:
100%
;
padding
:
15px
;
padding
:
15px
;
margin-bottom
:
10px
;
@media
(
min-width
:
$bp-screen-md
)
{
@media
(
min-width
:
$bp-screen-md
)
{
height
:
auto
;
height
:
auto
;
...
@@ -445,6 +444,7 @@
...
@@ -445,6 +444,7 @@
.section
{
.section
{
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
space-between
;
justify-content
:
space-between
;
@media
(
min-width
:
$bp-screen-md
)
{
@media
(
min-width
:
$bp-screen-md
)
{
...
@@ -452,6 +452,10 @@
...
@@ -452,6 +452,10 @@
}
}
}
}
.section
:not
(
:last-child
)
{
margin-bottom
:
$baseline
/
2
;
}
.section
:not
(
:first-child
)
{
.section
:not
(
:first-child
)
{
margin-top
:
0
;
margin-top
:
0
;
}
}
...
@@ -461,10 +465,14 @@
...
@@ -461,10 +465,14 @@
.course-title
{
.course-title
{
font-size
:
1em
;
font-size
:
1em
;
color
:
palette
(
primary
,
base
);
font-weight
:
600
;
font-weight
:
600
;
text-decoration
:
underline
;
margin
:
0
;
margin
:
0
;
.course-title-link
,
.course-title-link
:visited
{
color
:
palette
(
primary
,
base
);
text-decoration
:
underline
;
}
}
}
.run-period
{
.run-period
{
...
...
lms/templates/dashboard.html
View file @
badb1f84
...
@@ -34,6 +34,7 @@ from student.models import CourseEnrollment
...
@@ -34,6 +34,7 @@ from student.models import CourseEnrollment
</script>
</script>
% endfor
% endfor
% if course_entitlements:
% if course_entitlements:
<!-- This is a temporary solution before we land a fix to load these through Webpack, tracked by LEARNER-3483 -->
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/popper.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/popper.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/bootstrap.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/bootstrap.js')}"
></script>
% endif
% endif
...
@@ -141,9 +142,9 @@ from student.models import CourseEnrollment
...
@@ -141,9 +142,9 @@ from student.models import CourseEnrollment
'
session_id
'
:
course
['
key
'],
'
session_id
'
:
course
['
key
'],
'
enrollment_end
'
:
course
['
enrollment_end
'],
'
enrollment_end
'
:
course
['
enrollment_end
'],
'
pacing_type
'
:
course
['
pacing_type
'],
'
pacing_type
'
:
course
['
pacing_type
'],
'
session_start_advertised
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
advertised_start
,
'
advertised_start
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
advertised_start
,
'
s
ession_s
tart
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
start
,
'
start
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
start
,
'
session_
end
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
end
,
'
end
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
end
,
}
for
course
in
course_entitlement_available_sessions
[
str
(
entitlement
.
uuid
)]]
}
for
course
in
course_entitlement_available_sessions
[
str
(
entitlement
.
uuid
)]]
if
is_fulfilled_entitlement:
if
is_fulfilled_entitlement:
#
If
the
user
has
a
fulfilled
entitlement
,
pass
through
the
entitlements
CourseEnrollment
object
#
If
the
user
has
a
fulfilled
entitlement
,
pass
through
the
entitlements
CourseEnrollment
object
...
...
lms/templates/dashboard/_dashboard_course_listing.html
View file @
badb1f84
...
@@ -291,8 +291,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
...
@@ -291,8 +291,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
enterCourseBtn: '${ '#course-card-' + str(course_card_index) + ' .enter-course' | n, js_escaped_string }',
enterCourseBtn: '${ '#course-card-' + str(course_card_index) + ' .enter-course' | n, js_escaped_string }',
availableSessions: '${ entitlement_available_sessions | n, dump_js_escaped_json }',
availableSessions: '${ entitlement_available_sessions | n, dump_js_escaped_json }',
entitlementUUID: '${ entitlement.course_uuid | n, js_escaped_string }',
entitlementUUID: '${ entitlement.course_uuid | n, js_escaped_string }',
currentSessionId: '${ entitlement_session.course_id if entitlement_session else '' | n, js_escaped_string }',
currentSessionId: '${ entitlement_session.course_id if entitlement_session else "" | n, js_escaped_string }',
userId: '${ user.id | n, js_escaped_string }',
enrollUrl: '${ reverse('entitlements_api:v1:enrollments', args=[str(entitlement.uuid)]) | n, js_escaped_string }',
enrollUrl: '${ reverse('entitlements_api:v1:enrollments', args=[str(entitlement.uuid)]) | n, js_escaped_string }',
courseHomeUrl: '${ course_target | n, js_escaped_string }'
courseHomeUrl: '${ course_target | n, js_escaped_string }'
});
});
...
...
lms/templates/learner_dashboard/course_card.underscore
View file @
badb1f84
<div class="section">
<div class="section"
id="course-<%-uuid%>"
>
<div class="course-meta-container">
<div class="course-meta-container">
<div class="course-content">
<div class="course-content">
<div class="course-details">
<div class="course-details">
<h5 class="course-title">
<h5 class="course-title">
<% if (
marketing_url || course_url
) { %>
<% if (
(marketing_url || course_url) && !is_unfulfilled_entitlement
) { %>
<a href="<%- marketing_url || course_url %>" class="course-title-link">
<a href="<%- marketing_url || course_url %>" class="course-title-link">
<%- title %>
<%- title %>
</a>
</a>
...
@@ -12,11 +12,14 @@
...
@@ -12,11 +12,14 @@
<% } %>
<% } %>
</h5>
</h5>
<div class="course-text">
<div class="course-text">
<% if (enrolled) { %>
<% if (enrolled
&& !user_entitlement
) { %>
<span class="enrolled"><%- enrolled %>: </span>
<span class="enrolled"><%- enrolled %>: </span>
<% } %>
<% } %>
<% if (dateString) { %>
<% if (dateString
&& !is_unfulfilled_entitlement
) { %>
<span class="run-period"><%- dateString %></span>
<span class="run-period"><%- dateString %></span>
<% if (user_entitlement && !is_unfulfilled_entitlement) { %>
<button class="change-session btn-link" aria-controls="change-session-<%-user_entitlement.uuid%>"> <%- gettext('Change Session')%></button>
<% } %>
<% } %>
<% } %>
</div>
</div>
</div>
</div>
...
@@ -24,6 +27,7 @@
...
@@ -24,6 +27,7 @@
</div>
</div>
<div class="course-certificate certificate-status"></div>
<div class="course-certificate certificate-status"></div>
</div>
</div>
<div class="course-entitlement-selection-container<% if (!is_unfulfilled_entitlement && user_entitlement) { %> hidden <% } %>"></div>
</div>
</div>
<div class="section action-msg-view"></div>
<div class="section action-msg-view"></div>
<div class="section upgrade-message"></div>
<div class="section upgrade-message"></div>
...
...
lms/templates/learner_dashboard/course_enroll.underscore
View file @
badb1f84
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
<%- gettext('View Course') %>
<%- gettext('View Course') %>
<% } %>
<% } %>
</a>
</a>
<% } else { %>
<% } else
if (!user_entitlement)
{ %>
<% if (enrollable_course_runs.length > 0) { %>
<% if (enrollable_course_runs.length > 0) { %>
<% if (enrollable_course_runs.length > 1) { %>
<% if (enrollable_course_runs.length > 1) { %>
<div class="run-select-container">
<div class="run-select-container">
...
...
lms/templates/learner_dashboard/course_entitlement.underscore
View file @
badb1f84
...
@@ -9,8 +9,8 @@
...
@@ -9,8 +9,8 @@
<div class="action-controls">
<div class="action-controls">
<select class="session-select" aria-label="<%- StringUtils.interpolate( gettext('Session Selection Dropdown for {courseName}'), { courseName: courseName }) %>">
<select class="session-select" aria-label="<%- StringUtils.interpolate( gettext('Session Selection Dropdown for {courseName}'), { courseName: courseName }) %>">
<% _.each(availableSessions, function(session) { %>
<% _.each(availableSessions, function(session) { %>
<option data-session_id="<%- session.session_id %>">
<option data-session_id="<%- session.session_id
|| session.key
%>">
<% if (
session.session_id
=== currentSessionId) { %>
<% if (
(session.session_id || session.key)
=== currentSessionId) { %>
<%- StringUtils.interpolate( gettext('{sessionDates} - Currently Selected'), {sessionDates: session.session_dates}) %>
<%- StringUtils.interpolate( gettext('{sessionDates} - Currently Selected'), {sessionDates: session.session_dates}) %>
<% } else if (session.enrollment_end){ %>
<% } else if (session.enrollment_end){ %>
<%- StringUtils.interpolate( gettext('{sessionDates} (Open until {enrollmentEnd})'), {sessionDates: session.session_dates, enrollmentEnd: session.enrollment_end}) %>
<%- StringUtils.interpolate( gettext('{sessionDates} (Open until {enrollmentEnd})'), {sessionDates: session.session_dates, enrollmentEnd: session.enrollment_end}) %>
...
...
lms/templates/learner_dashboard/program_details_fragment.html
View file @
badb1f84
...
@@ -9,6 +9,10 @@ from openedx.core.djangolib.js_utils import (
...
@@ -9,6 +9,10 @@ from openedx.core.djangolib.js_utils import (
%
>
%
>
<
%
block
name=
"js_extra"
>
<
%
block
name=
"js_extra"
>
<!-- This is a temporary solution before we land a fix to load these through Webpack, tracked by LEARNER-3483 -->
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/popper.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/bootstrap.js')}"
></script>
<
%
static:require_module
module_name=
"js/learner_dashboard/program_details_factory"
class_name=
"ProgramDetailsFactory"
>
<
%
static:require_module
module_name=
"js/learner_dashboard/program_details_factory"
class_name=
"ProgramDetailsFactory"
>
ProgramDetailsFactory({
ProgramDetailsFactory({
programData: ${program_data | n, dump_js_escaped_json},
programData: ${program_data | n, dump_js_escaped_json},
...
...
openedx/core/djangoapps/programs/utils.py
View file @
badb1f84
...
@@ -222,15 +222,26 @@ class ProgramProgressMeter(object):
...
@@ -222,15 +222,26 @@ class ProgramProgressMeter(object):
completed
,
in_progress
,
not_started
=
[],
[],
[]
completed
,
in_progress
,
not_started
=
[],
[],
[]
for
course
in
program_copy
[
'courses'
]:
for
course
in
program_copy
[
'courses'
]:
try
:
entitlement
=
CourseEntitlement
.
objects
.
get
(
user
=
self
.
user
,
course_uuid
=
course
[
'uuid'
])
except
CourseEntitlement
.
DoesNotExist
:
entitlement
=
None
if
self
.
_is_course_complete
(
course
):
if
self
.
_is_course_complete
(
course
):
completed
.
append
(
course
)
completed
.
append
(
course
)
elif
self
.
_is_course_enrolled
(
course
):
elif
self
.
_is_course_enrolled
(
course
)
or
entitlement
:
course_in_progress
=
self
.
_is_course_in_progress
(
now
,
course
)
# Show all currently enrolled courses and entitlements as in progress
if
course_in_progress
:
if
entitlement
:
course
[
'user_entitlement'
]
=
entitlement
.
to_dict
()
course
[
'enroll_url'
]
=
reverse
(
'entitlements_api:v1:enrollments'
,
args
=
[
str
(
entitlement
.
uuid
)])
in_progress
.
append
(
course
)
in_progress
.
append
(
course
)
else
:
else
:
course
[
'expired'
]
=
not
course_in_progress
course_in_progress
=
self
.
_is_course_in_progress
(
now
,
course
)
not_started
.
append
(
course
)
if
course_in_progress
:
in_progress
.
append
(
course
)
else
:
course
[
'expired'
]
=
not
course_in_progress
not_started
.
append
(
course
)
else
:
else
:
not_started
.
append
(
course
)
not_started
.
append
(
course
)
...
...
themes/edx.org/lms/templates/dashboard.html
View file @
badb1f84
...
@@ -35,6 +35,7 @@ from student.models import CourseEnrollment
...
@@ -35,6 +35,7 @@ from student.models import CourseEnrollment
</script>
</script>
% endfor
% endfor
% if course_entitlements:
% if course_entitlements:
<!-- This is a temporary solution before we land a fix to load these through Webpack, tracked by LEARNER-3483 -->
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/popper.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/popper.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/bootstrap.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('common/js/vendor/bootstrap.js')}"
></script>
% endif
% endif
...
@@ -136,9 +137,9 @@ from student.models import CourseEnrollment
...
@@ -136,9 +137,9 @@ from student.models import CourseEnrollment
'
session_id
'
:
course
['
key
'],
'
session_id
'
:
course
['
key
'],
'
enrollment_end
'
:
course
['
enrollment_end
'],
'
enrollment_end
'
:
course
['
enrollment_end
'],
'
pacing_type
'
:
course
['
pacing_type
'],
'
pacing_type
'
:
course
['
pacing_type
'],
'
session_start_advertised
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
advertised_start
,
'
advertised_start
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
advertised_start
,
'
s
ession_s
tart
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
start
,
'
start
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
start
,
'
session_
end
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
end
,
'
end
'
:
CourseOverview
.
get_from_id
(
CourseKey
.
from_string
(
course
['
key
'])).
end
,
}
for
course
in
course_entitlement_available_sessions
[
str
(
entitlement
.
uuid
)]]
}
for
course
in
course_entitlement_available_sessions
[
str
(
entitlement
.
uuid
)]]
if
is_fulfilled_entitlement:
if
is_fulfilled_entitlement:
#
If
the
user
has
a
fulfilled
entitlement
,
pass
through
the
entitlements
CourseEnrollment
object
#
If
the
user
has
a
fulfilled
entitlement
,
pass
through
the
entitlements
CourseEnrollment
object
...
...
webpack.common.config.js
View file @
badb1f84
...
@@ -25,6 +25,8 @@ module.exports = {
...
@@ -25,6 +25,8 @@ module.exports = {
// LMS
// LMS
SingleSupportForm
:
'./lms/static/support/jsx/single_support_form.jsx'
,
SingleSupportForm
:
'./lms/static/support/jsx/single_support_form.jsx'
,
AlertStatusBar
:
'./lms/static/js/accessible_components/StatusBarAlert.jsx'
,
AlertStatusBar
:
'./lms/static/js/accessible_components/StatusBarAlert.jsx'
,
Bootstrap
:
'./lms/static/common/js/vendor/bootstrap.js'
,
EntitlementView
:
'./lms/static/js/learner_dashboard/views/course_entitlement_view.js'
,
// Features
// Features
CourseGoals
:
'./openedx/features/course_experience/static/course_experience/js/CourseGoals.js'
,
CourseGoals
:
'./openedx/features/course_experience/static/course_experience/js/CourseGoals.js'
,
...
@@ -63,6 +65,9 @@ module.exports = {
...
@@ -63,6 +65,9 @@ module.exports = {
jQuery
:
'jquery'
,
jQuery
:
'jquery'
,
'window.jQuery'
:
'jquery'
'window.jQuery'
:
'jquery'
}),
}),
new
webpack
.
ProvidePlugin
({
Popper
:
'popper.js'
}),
// Note: Until karma-webpack releases v3, it doesn't play well with
// Note: Until karma-webpack releases v3, it doesn't play well with
// the CommonsChunkPlugin. We have a kludge in karma.common.conf.js
// the CommonsChunkPlugin. We have a kludge in karma.common.conf.js
...
@@ -169,6 +174,7 @@ module.exports = {
...
@@ -169,6 +174,7 @@ module.exports = {
gettext
:
'gettext'
,
gettext
:
'gettext'
,
jquery
:
'jQuery'
,
jquery
:
'jQuery'
,
logger
:
'Logger'
,
logger
:
'Logger'
,
popper
:
'Popper'
,
underscore
:
'_'
,
underscore
:
'_'
,
URI
:
'URI'
URI
:
'URI'
},
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment