Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exports[`Tutor Layout renders and matches snapshot 1`] = `
<TutorLayout>
<MobXProvider topNavbar={{...}} courseContext={{...}} bottomNavbar={{...}} setSecondaryTopControls={[Function: setSecondaryTopControls] { isMobxAction: true }}>
<styled.div hasNavbar={true}>
<div className=\\"sc-ieebsP eYGqFg\\">
<div className=\\"sc-dJjZJu dnIMEJ\\">
<Navbar area=\\"header\\" context={{...}} isDocked={false} className=\\"\\">
<styled.nav area=\\"header\\" shouldHideNavbar={[undefined]} isDocked={false} className=\\"tutor-navbar nav-\\">
<nav className=\\"sc-gsDJrp djLbyF tutor-navbar nav-\\">
Expand All @@ -28,7 +28,7 @@ exports[`Tutor Layout renders and matches snapshot 1`] = `
<LinkAnchor onClick={[undefined]} className=\\"brand\\" aria-label=\\"dashboard\\" href=\\"/courses\\" navigate={[Function: navigate]}>
<a className=\\"brand\\" aria-label=\\"dashboard\\" href=\\"/courses\\" onClick={[Function: onClick]}>
<styled.svg viewBox=\\"0 0 264.62 40.7\\">
<svg viewBox=\\"0 0 264.62 40.7\\" className=\\"sc-ksdxAp gxpANX\\">
<svg viewBox=\\"0 0 264.62 40.7\\" className=\\"sc-hBURRC dGZWDW\\">
<defs>
<style />
</defs>
Expand Down Expand Up @@ -214,7 +214,7 @@ exports[`Tutor Layout renders and matches snapshot 1`] = `
</Observer>
</inject(CourseNagModal)>
<styled.div className=\\"\\" hasFooter={false} hasNavbar={true}>
<div className=\\"sc-dJjZJu eARDFU\\">
<div className=\\"sc-hGPAah cdJMum\\">
<Memo(wrappedComponent) app={[undefined]} />
<p>
hi i am body
Expand Down
28 changes: 24 additions & 4 deletions tutor/specs/e2e/soc3e.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ describe('Soc3e Announcement and Launch', () => {
await setTimeouts()
await loginAs('reviewteacher')
await visitPage(page, '/course/1')
await page.waitForNavigation()
await page.waitForSelector('css=.course-page')
await disableTours(page)
await page.evaluate(() => {
const offering = window._MODELS.courses.get(1).offering
offering.os_book_id = offering.SOC2E_BOOK_ID
offering.appearance_code = 'intro_sociology'
window._MODELS.offerings.get(2).os_book_id = ''
window._MODELS.offerings.get(2).is_available = false
window._MODELS.settings.set('soc3eBannerDismissed', null)
window._MODELS.settings.set('soc3eOverlayViewedAt', null)
})
})

it('displays a banner on a Sociology 2e dashboard before 3e is available', async () => {
// Don't display it when Soc3e doesn't exist
await expect(page).not.toHaveText('Introduction to Sociology 3e')
await expect(page).not.toHaveSelector('testEl=sociology-3e-banner', { timeout: 30 })

// Display it when Soc3e exists but is not yet available
await page.evaluate(() => {
Expand All @@ -27,12 +30,29 @@ describe('Soc3e Announcement and Launch', () => {
offering.is_available = false
})

await expect(page).toHaveText('Introduction to Sociology 3e')
await expect(page).toHaveSelector('testEl=sociology-3e-banner')

// Don't display it when Soc3e exists and is available
await page.evaluate(() => {
window._MODELS.offerings.get(2).is_available = true
})
await expect(page).not.toHaveText('Introduction to Sociology 3e')
await expect(page).not.toHaveSelector('testEl=sociology-3e-banner')
})

it('displays an overlay on a Sociology 2e offering and dashboard when 3e is available', async () => {
await page.evaluate(() => {
const offering = window._MODELS.offerings.get(2)
offering.os_book_id = offering.SOC3E_BOOK_ID
offering.is_available = true
})
await expect(page).toHaveSelector('testEl=sociology-3e-overlay')
await page.click('testEl=soc3e-close-overlay')
await expect(page).not.toHaveSelector('testEl=sociology-3e-overlay', { timeout: 10 })
await page.evaluate(() => {
const date = new Date()
date.setDate(date.getDate() - 120)
window._MODELS.settings.set('soc3eOverlayViewedAt', date)
})
await expect(page).toHaveSelector('testEl=sociology-3e-overlay')
})
})
2 changes: 1 addition & 1 deletion tutor/src/components/tours/custom/drop-any.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const DropQuestionRelocated = (props: any) => {
<li>Click <Icon type="minus-circle" /></li>
</ol>
</div>
</StyledGreenTooltip >
</StyledGreenTooltip>
)
}

Expand Down
44 changes: 3 additions & 41 deletions tutor/src/components/tours/step.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import {
React, PropTypes, observer,
} from 'vendor';
import Spotlight from './spotlight';
import Floater from 'react-floater';
import STEPS from './custom';
import { colors } from 'theme';
import TutorTooltip from '../tutor-tooltip';

@observer
export default class TourStep extends React.Component {
Expand All @@ -14,55 +13,18 @@ export default class TourStep extends React.Component {
ride: PropTypes.object.isRequired,
}

styles = {
floater: {
maxWidth: '100%',
},
container: {
padding: 0,
borderRadius: '4px',
},
options: {
zIndex: 1501,
},
};

classNameStyles = {
green: {
arrow: {
color: colors.secondary,
spread: 16,
length: 10,
},
},
greenNoBody: {
arrow: {
color: colors.secondary,
spread: 16,
length: 10,
margin: 20,
},
container: {
minHeight: 0,
padding: 0,
},
},
};


render() {
const { step, ride } = this.props;
const Step = STEPS[step.customComponent || 'Standard'];
const styles = { ...this.styles, ...this.classNameStyles[step.className] };

const tip = (
<Floater
<TutorTooltip
open={true}
debug={ride.context.emitDebugInfo}
autoOpen={true}
key={step.anchor_id}
target={step.target}
styles={styles}
variant={step.variant}
disableAnimation={true}
placement={step.placement}
content={<Step step={step} ride={ride} />}
Expand Down
158 changes: 158 additions & 0 deletions tutor/src/components/tutor-tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { React, styled, css, observer } from 'vendor'
import { Icon } from 'shared'
import { colors } from '../theme'
import Floater from 'react-floater'
import { omit, merge } from 'lodash'

const floaterStyles = {
default: {
floater: {
maxWidth: '100%',
},
container: {
padding: 0,
borderRadius: '4px',
},
options: {
zIndex: 1501,
},
},
gray: {
arrow: {
color: colors.neutral.std,
spread: 16,
length: 10,
},
container: {
padding: 0,
borderRadius: '4px',
},
},
green: {
arrow: {
color: colors.secondary,
spread: 16,
length: 10,
},
container: {
minHeight: 0,
padding: 0,
},
},
greenNoBody: {
arrow: {
color: colors.secondary,
spread: 16,
length: 10,
margin: 20,
},
container: {
minHeight: 0,
padding: 0,
},
},
};

const StyledContent = styled.div<TutorTooltipProps>`
.header {
${(props: TutorTooltipProps) => props.variant === Variants.Green && css`
background: ${colors.secondary};
`}
${(props: TutorTooltipProps) => props.variant === Variants.Gray && css`
background: ${colors.neutral.std};
`}
color: #fff;
padding: 10px 20px;
font-size: 1.6rem;
line-height: 2rem;
letter-spacing: -0.64px;
position: relative;

.close {
position: absolute;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.2);
background-blend-mode: multiply;
min-width: 4rem;
color: #fff;
}

button {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;

svg {
margin: 0;
width: 11px;
color: #fff;
}
}
}


.body {
${(props: TutorTooltipProps) => props.variant === Variants.Gray && css`
background: ${colors.neutral.lighter};
`}

font-size: 1.4rem;
line-height: 2rem;
padding: 16px 20px 24px;
background: #fff;
max-width: 272px;
letter-spacing: -0.4px;
}
`

enum Variants {
Gray = 'gray',
Green = 'green',
}

interface TutorTooltipProps {
variant?: Variants
header?: string
body?: any
children: any
open?: boolean
autoOpen?: boolean
onClose?(): any
styles?: any
disableFlip?: boolean
placement?: any
offset?: number
}

const TutorTooltip = observer((props: TutorTooltipProps) => {
const { header, body, onClose, variant, styles } = props
const customStyles = merge(floaterStyles[variant || 'default'], styles)
const floaterProps = omit(props, ['styles', 'variant', 'header', 'body'])

const content = (
<StyledContent variant={variant}>
<div className="header">
{header}
<button onClick={onClose} aria-label="Close" className="close">
<Icon type="close" />
</button>
</div>
<div className="body">
{body}
</div>
</StyledContent>
)
return (
<Floater
content={content}
styles={customStyles}
{...floaterProps}
/>
)
})

export default TutorTooltip
export { Variants }
2 changes: 2 additions & 0 deletions tutor/src/models/course/information.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,6 @@ export const CourseInformation = {

openstaxSubjects: 'https://openstax.org/subjects/view-all',

soc3eFaq: 'https://openstax.secure.force.com/help/articles/FAQ/Introduction-to-Sociology-3e-Frequently-Asked-Questions',

};
6 changes: 5 additions & 1 deletion tutor/src/models/course/offerings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ export class OfferingsMap extends Map<ID, Offering> {
return this.available.where(c => c.appearance_code == 'biology_2e');
}

@computed get sociology3e() {
return this.available.where(c => c.isSociology3e)
}

@computed get soc3eExists() {
return this.where(c => c.isSociology3e).any
}

@computed get soc3eAvailable() {
return this.available.where(c => c.isSociology3e).any
return this.sociology3e.any
}

@action bootstrap(items: OfferingData[]) {
Expand Down
1 change: 1 addition & 0 deletions tutor/src/screens/my-courses/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const StyledMyCoursesDashboard = styled.div`
padding-top: 2.4rem;
padding: 2.4rem 3.2rem 6.4rem;
min-height: 40rem;
position: relative;
h3 {
color: ${colors.neutral.std};
}
Expand Down
5 changes: 4 additions & 1 deletion tutor/src/screens/my-courses/dashboard/offering-block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import CreateACourse from './create-course'
import CoursePreview from './preview-course'
import ViewCourse from './view-course'
import Resource from './resource'

import Sociology3eOfferingTooltip from './sociology-3e-offering-tooltip'
import Sociology3eOverlay from './sociology-3e-overlay'

const sortByCourseEndsAt = (courseA: Course, courseB: Course) => {
if (courseA.ends_at.isAfter(courseB.ends_at)) { return 1 }
Expand Down Expand Up @@ -191,6 +192,8 @@ const OfferingBlock: React.FC<OfferingBlockProps> = ({ offering, courses, swapOf
return (
<div className={cn('offering-container', { 'is-edit-mode': isEditMode })} data-offering-id={offering.id} data-test-id="offering-container">
{editModeIcons}
<Sociology3eOverlay offering={offering} />
<Sociology3eOfferingTooltip offering={offering} />
<h3>{offering.title}</h3>
<Tabs
tabs={['current', 'past', 'resources']}
Expand Down
Loading