Skip to content

Commit

Permalink
feat: Added trial url and days to the chat intro
Browse files Browse the repository at this point in the history
  • Loading branch information
rijuma committed Dec 13, 2024
1 parent 484ef9d commit b0289f8
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 74 deletions.
13 changes: 11 additions & 2 deletions src/components/Disclosure/Disclosure.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
background-color: variables.$dark-green;
font-family: Inter, Arial, sans-serif;
padding: 2rem;
display: flex;
flex-direction: column;

h2 {
font-size: 1.375rem;
Expand Down Expand Up @@ -44,7 +46,6 @@

.disclaimer {
font-size: 0.75rem;
margin-bottom: 7.5rem;
}

.trial-period {
Expand Down Expand Up @@ -75,7 +76,15 @@
.trial-upgrade {
background: #D74000;
border-radius: 99rem;
font-size: 0.875rem;
font-size: 0
.875rem;
}

.pgn__form-group {
margin: 0;
}
.pgn__form-control-decorator-group {
margin: 0;
}
}

119 changes: 67 additions & 52 deletions src/components/Disclosure/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,82 @@ import { QuestionAnswerOutline, LightbulbCircle, AutoAwesome } from '@openedx/pa
import { ensureConfig, getConfig } from '@edx/frontend-platform/config';

import './Disclosure.scss';
import { useCourseUpgrade, useTrackEvent } from '../../hooks';

ensureConfig(['PRIVACY_POLICY_URL']);

const Disclosure = ({ children, showTrial }) => (
<div className="disclosure d-flex flex-column align-items-stretch">
<h2 className="text-light-100">
Xpert Learning Assistant
</h2>
<h3 className="small py-2">An AI-powered educational tool</h3>
<div className="d-flex flex-column">
<div className="text-light-100 d-flex flex-row mb-3">
<Icon src={LightbulbCircle} className="bullet-icon" />
<div>
Understand a concept<br />
<small>“How does photosynthesis work?”</small>
</div>
</div>
<div className="text-light-100 d-flex flex-row mb-4">
<Icon src={QuestionAnswerOutline} className="bullet-icon" />
<div>
Summarize your learning<br />
<small>“Can you help me review pivot tables?”</small>
</div>
</div>
</div>
{showTrial ? (
<div className="trial-period">
<div className="trial-period-content">
<div className="d-flex flex-row text-light-100">
<Icon src={AutoAwesome} className="bullet-icon bullet-icon" />
<small>
Free trial, then upgrade course for full access to Xpert features.
</small>
const Disclosure = ({ children }) => {
const { upgradeable, upgradeUrl, auditTrialLengthDays } = useCourseUpgrade();
const { track } = useTrackEvent();

const handleClick = () => track('edx.ui.lms.learning_assistant.message');
const freeDays = auditTrialLengthDays === 1 ? '1 day' : `${auditTrialLengthDays} days`;

return (
<section className="disclosure d-flex flex-column align-items-stretch">
<h2 className="text-light-100">
Xpert Learning Assistant
</h2>
<div className="info">
<h3 className="small py-2">An AI-powered educational tool</h3>
<div className="d-flex flex-column">
<div className="text-light-100 d-flex flex-row mb-3">
<Icon src={LightbulbCircle} className="bullet-icon" />
<div>
Understand a concept<br />
<small>“How does photosynthesis work?”</small>
</div>
</div>
<div className="text-light-100 d-flex flex-row mb-4">
<Icon src={QuestionAnswerOutline} className="bullet-icon" />
<div>
Summarize your learning<br />
<small>“Can you help me review pivot tables?”</small>
</div>
</div>
<Button className="trial-upgrade mt-3" block>Upgrade now</Button>
</div>
{upgradeable ? (
<div className="trial-period">
<div className="trial-period-content">
<div className="d-flex flex-row text-light-100">
<Icon src={AutoAwesome} className="bullet-icon bullet-icon" />
<small>
Free for {freeDays}, then upgrade course for full access to Xpert features.
</small>
</div>
<Button
onClick={handleClick}
href={upgradeUrl}
className="trial-upgrade mt-3"
block
>
Upgrade now
</Button>
</div>
</div>
) : null}
<p className="disclaimer small text-light-100 py-3">
Note: This chat is AI generated, mistakes are possible.
By using it you agree that edX may create a record of this chat.
Your personal data will be used as described in our &nbsp;
<Hyperlink
className="privacy-policy-link text-light-100"
destination={getConfig().PRIVACY_POLICY_URL}
>
privacy policy
</Hyperlink>
.
</p>
</div>
) : null}
<p className="disclaimer small text-light-100 py-3">
Note: This chat is AI generated, mistakes are possible.
By using it you agree that edX may create a record of this chat.
Your personal data will be used as described in our &nbsp;
<Hyperlink
className="privacy-policy-link text-light-100"
destination={getConfig().PRIVACY_POLICY_URL}
>
privacy policy
</Hyperlink>
.
</p>
{children}
</div>
);
<footer>
{children}
</footer>
</section>
);
};

Disclosure.propTypes = {
showTrial: PropTypes.bool,
children: PropTypes.node.isRequired,
};

Disclosure.defaultProps = {
showTrial: false,
};

export default Disclosure;
2 changes: 1 addition & 1 deletion src/components/MessageForm/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const MessageForm = ({ courseId, shouldAutofocus, unitId }) => {
);

return (
<Form className="message-form w-100 pl-2" onSubmit={handleSubmitMessage} data-testid="message-form">
<Form className="message-form w-100" onSubmit={handleSubmitMessage} data-testid="message-form">
<Form.Group>
<Form.Control
data-hj-suppress
Expand Down
4 changes: 3 additions & 1 deletion src/components/Sidebar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ const Sidebar = ({
invertColors
data-testid="close-button"
/>
{disclosureAcknowledged ? (getSidebar()) : (<Disclosure>{getMessageForm()}</Disclosure>)}
{disclosureAcknowledged
? (getSidebar())
: (<Disclosure>{getMessageForm()}</Disclosure>)}
</div>
)
);
Expand Down
9 changes: 9 additions & 0 deletions src/context/course-info-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createContext } from 'react';

export const CourseInfoContext = createContext('course-info', {
courseId: null,
unitId: null,
isUpgradeEligible: false,
});

export const CourseInfoProvider = CourseInfoContext.Provider;
1 change: 1 addition & 0 deletions src/context/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './course-info-context';
5 changes: 5 additions & 0 deletions src/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const initialState = {
sidebarIsOpen: false,
isEnabled: false,
auditTrial: {},
auditTrialLengthDays: null,
};

export const learningAssistantSlice = createSlice({
Expand Down Expand Up @@ -48,6 +49,9 @@ export const learningAssistantSlice = createSlice({
setAuditTrial: (state, { payload }) => {
state.auditTrial = payload;
},
setAuditTrialLengthDays: (state, { payload }) => {
state.auditTrialLengthDays = payload;
},
},
});

Expand All @@ -62,6 +66,7 @@ export const {
setSidebarIsOpen,
setIsEnabled,
setAuditTrial,
setAuditTrialLengthDays,
} = learningAssistantSlice.actions;

export const {
Expand Down
3 changes: 3 additions & 0 deletions src/data/thunks.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
setSidebarIsOpen,
setIsEnabled,
setAuditTrial,
setAuditTrialLengthDays,
} from './slice';
import { OPTIMIZELY_PROMPT_EXPERIMENT_KEY } from './optimizely';

Expand Down Expand Up @@ -134,6 +135,8 @@ export function getLearningAssistantChatSummary(courseId) {
if (Object.keys(auditTrial).length !== 0) {
dispatch(setAuditTrial(auditTrial));
}

if (data.audit_trial_length_days) { dispatch(setAuditTrialLengthDays(data.audit_trial_length_days)); }
} catch (error) {
dispatch(setApiError());
}
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint-disable import/prefer-default-export */
export { default as useCourseUpgrade } from './use-course-upgrade';
export { default as useTrackEvent } from './use-track-event';
23 changes: 23 additions & 0 deletions src/hooks/use-course-upgrade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useContext } from 'react';
import { useModel } from '@src/generic/model-store'; // eslint-disable-line import/no-unresolved
import { useSelector } from 'react-redux';
import { CourseInfoContext } from '../context';

export default function useCourseUpgrade() {
const { courseId, isUpgradeEligible } = useContext(CourseInfoContext);
const { offer } = useModel('coursewareMeta', courseId);
const { verifiedMode } = useModel('courseHomeMeta', courseId);
const {
auditTrialLengthDays,
} = useSelector(state => state.learningAssistant);

const upgradeUrl = offer?.upgradeUrl || verifiedMode?.upgradeUrl;

if (!isUpgradeEligible || !upgradeUrl) { return { upgradeable: false }; }

return {
upgradeable: true,
auditTrialLengthDays,
upgradeUrl,
};
}
20 changes: 20 additions & 0 deletions src/hooks/use-track-event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useContext } from 'react';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { CourseInfoContext } from '../context';

export default function useTrackEvent() {
const { courseId, moduleId } = useContext(CourseInfoContext);
const { userId } = getAuthenticatedUser();

const track = (event, details) => {
sendTrackEvent(event, {
course_id: courseId,
user_id: userId,
module_id: moduleId,
...details,
});
};

return { track };
}
43 changes: 25 additions & 18 deletions src/widgets/Xpert.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import PropTypes from 'prop-types';
import { useEffect } from 'react';
import { useEffect, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { updateSidebarIsOpen, getLearningAssistantChatSummary } from '../data/thunks';
import ToggleXpert from '../components/ToggleXpertButton';
import Sidebar from '../components/Sidebar';
import { ExperimentsProvider } from '../experiments';
import { CourseInfoProvider } from '../context';

const Xpert = ({
courseId,
contentToolsEnabled,
unitId,
isUpgradeEligible, // eslint-disable-line no-unused-vars
isUpgradeEligible,
}) => {
const dispatch = useDispatch();
const courseInfo = useMemo(
() => ({ courseId, unitId, isUpgradeEligible }),
[courseId, unitId, isUpgradeEligible],
);

const {
isEnabled,
Expand All @@ -40,22 +45,24 @@ const Xpert = ({
};

return isEnabled ? (
<ExperimentsProvider>
<>
<ToggleXpert
courseId={courseId}
isOpen={sidebarIsOpen}
setIsOpen={setSidebarIsOpen}
contentToolsEnabled={contentToolsEnabled}
/>
<Sidebar
courseId={courseId}
isOpen={sidebarIsOpen}
setIsOpen={setSidebarIsOpen}
unitId={unitId}
/>
</>
</ExperimentsProvider>
<CourseInfoProvider value={courseInfo}>
<ExperimentsProvider>
<>
<ToggleXpert
courseId={courseId}
isOpen={sidebarIsOpen}
setIsOpen={setSidebarIsOpen}
contentToolsEnabled={contentToolsEnabled}
/>
<Sidebar
courseId={courseId}
isOpen={sidebarIsOpen}
setIsOpen={setSidebarIsOpen}
unitId={unitId}
/>
</>
</ExperimentsProvider>
</CourseInfoProvider>
) : null;
};

Expand Down

0 comments on commit b0289f8

Please sign in to comment.