* wip: courses * fix: update course sidebar * wip * fix: merge lessons * wip * wip: course footer * wip * fix: refactor layout * fix: refactor * feat: course progress * fix: update current lesson store * fix: refactor props * wip * wip * feat: course certificate * wip: course rating * wip: course notes * wip * feat: implement course notes * feat: make card clickable * fix: add hover background * fix: refactor course layout * fix: resizeable * fix: go back on save * feat: delete confimation * wip * feat: chat UI * fix: lesson complete guard issue * wip: add public json files * wip: course ai * fix: loading card * Fix failing dev without internet * Light mode and UI changes * Update UI * Update course UI * Add chapter page * Improve sidebar of course * Update navigation: * Update quiz view * Improve UI for quiz attempts * Remove unnecessary console.logs * Add progress loading skeletons * Update UI * Change background color of editor * Fix line color not applied on editor * UI updates * feat: empty view * feat: course ai token limit * feat: handle auth users * wip * feat: course landing page * wip * Add first chapter of SQL * Add introduction chapter * Add quiz for introduction * Add expressions in select * Add content for DISTINCT * Add filter with where * Add lesson about limit and offset * Add lesson for handling null values * Add lesson about comments * Add challenges * Add challenge * Add challenge * Add challenge * Add challenge 7 * Add creating tables lesson * Add common data types lesson * Add data types in sqlite * Add more on data types lesson * feat: course landing page * Add more on numeric types * Update * Add lesson about temporal data types * Add constraints * Add primary keys chapter * Add modifying tables * Add dropping and truncating * Rewrite for PostgreSQL * Update numeric types to PostgreSQL * Improve temporal data type content * Improve temporal data type content * Add setup for temporal data * Improve challenges in SQL basics * Update challenge names * Add new challenges * Add temporal validation challenge * Add new constraint * Add modifying tables query * Removing table * Add insert operations lesson * Add updating data lesson * Add delete operations * Add inserting and updating challenges * Add lesson for cleaning up data * Update course title * Add relation data lesson * Add relationships and types * Add relationships and types * wip * Add joins lesson * Joins in queries * Add inner join details * Add join queries * Add inner join details * Add foreign key constraint lesson * Update composite foreign keys * Add lesson about foreign keys * Add lesson about set operation queries * Add lesson about set operation queries * Add set operator challenges * Add new challenge * Add view lesson * Add notes in views * Add inactive customer challenge * Add high value order challenge * gst * Add new challenges * Add readers like you challenge * Update inactive customer query * Update inactive customer query * Update inactive customer query * Update inactive customer query * Update inactive customer query * add challenge for same price books * Add aggregate functions introduction * Add basic aggregation lesson * Add basic aggregation lesson * Add introduction quiz * Add grouping lesson * Add grouping gotchas * Add grouping and filtering lesson * Add note for lesson * Add challenges for aggregate * Update aggregate challenge * Rearrange chapters * Add scalar functions lessons * Add numeric functions * Add date functions * Add conversion functions * Add conversion functions * Add logical functions chapter * Add exercises * Add new challenges * Add monthly sales analysis * Add subqueries and ctes * Update * Add correlated subqueries * Add common table expressions * Add common-table expressions * Add example * Add recursive CTEs * Add subquery challenge * Add latest category books challenge * Add challenges * Add bestseller rankings challenge * Add new customer analysis * Add daily sales report * Improve queries * Add introduction to window functions * Add over and partition * wip: billing page * Add ranking functions * Improve ranking functions * Add order by * Add window frames lesson * Add window frames explanation * Add challenges for window functions * Add price range analysis challenge * wip * wip: course enroll * fix: start learning * wip * wip * Enrollment changes * wip * wip * feat: mobile responsive * Changelog banner refactor * Update * Header for course * Header for what to expect * UI color * Table of contents * Icons on chapters * Change design for road to sql * Add sql course page * Add lesson content * Update UI * Expanded chapter row * Add course page * Refactor * Add spotlight * Improve features * Add course features * Add certificate note * Zoom in on the image * Update * Add floating purchase * Floating purchase indicatorg * Add about section * Update about section * Add FAQ section * Update UI * Add purchase power parity * Show purchasing power pricing * Add course login popup * Add course login popup * Add account button * Add trigger for course purchase * Course purchase param * Buy button changes * Add faqs * Add purchase trigger on reload * Landing verification * Make header responsive * Make course page upper half responsive * Full page is responsive * Fix login height bug * Responsiveness * Implement login after checkout * Remove unused code * Update dependenciesg * Update * fix: refetch mount to false * Remove unused code * Remove unused code * Remove unused code * Remove unused code * Remove unused code * Remove unused code * Remove unused * Add quizzes to chapters * Update course slug * Update dependencies * Add header for sql course --------- Co-authored-by: Arik Chakma <arikchangma@gmail.com>
128 lines
3.1 KiB
TypeScript
128 lines
3.1 KiB
TypeScript
type UtmParams = Partial<{
|
|
utmSource: string;
|
|
utmMedium: string;
|
|
utmCampaign: string;
|
|
utmContent: string;
|
|
utmTerm: string;
|
|
}>;
|
|
|
|
export function getUrlUtmParams(): UtmParams {
|
|
if (typeof window === 'undefined') {
|
|
return {};
|
|
}
|
|
|
|
const utmParams = new URLSearchParams(window.location.search);
|
|
const utmSource = utmParams.get('utm_source') ?? undefined;
|
|
const utmMedium = utmParams.get('utm_medium') ?? undefined;
|
|
const utmCampaign = utmParams.get('utm_campaign') ?? undefined;
|
|
const utmContent = utmParams.get('utm_content') ?? undefined;
|
|
const utmTerm = utmParams.get('utm_term') ?? undefined;
|
|
|
|
if (!utmSource || !utmCampaign) {
|
|
return {};
|
|
}
|
|
|
|
return {
|
|
utmSource: utmCampaign ? utmSource.toLowerCase() : undefined,
|
|
utmMedium: utmMedium ? utmMedium.toLowerCase() : undefined,
|
|
utmCampaign: utmCampaign ? utmCampaign.toLowerCase() : undefined,
|
|
utmContent: utmContent ? utmContent.toLowerCase() : undefined,
|
|
utmTerm: utmTerm ? utmTerm.toLowerCase() : undefined,
|
|
};
|
|
}
|
|
|
|
export function triggerUtmRegistration() {
|
|
const utmParams = getStoredUtmParams();
|
|
if (!utmParams.utmSource) {
|
|
return;
|
|
}
|
|
|
|
localStorage.removeItem('utm_params');
|
|
|
|
window.fireEvent({
|
|
category: 'UserRegistration',
|
|
action: `Registration: ${utmParams.utmSource || 'unknown'}-${utmParams.utmCampaign || 'unknown'}`,
|
|
label: `Registration: ${utmParams.utmSource || 'unknown'}-${utmParams.utmCampaign || 'unknown'}`,
|
|
});
|
|
}
|
|
|
|
export function getStoredUtmParams(): UtmParams {
|
|
if (typeof window === 'undefined') {
|
|
return {};
|
|
}
|
|
|
|
const utmParams = localStorage.getItem('utm_params');
|
|
if (!utmParams) {
|
|
return {};
|
|
}
|
|
|
|
return JSON.parse(utmParams);
|
|
}
|
|
|
|
export function getUrlParams() {
|
|
if (typeof window === 'undefined') {
|
|
return {};
|
|
}
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
const paramsObj: Record<string, any> = {};
|
|
for (const [key, value] of params.entries()) {
|
|
paramsObj[key] = value;
|
|
}
|
|
|
|
return paramsObj;
|
|
}
|
|
|
|
export function parseUrl(url: string) {
|
|
const parser = document.createElement('a');
|
|
parser.href = url;
|
|
|
|
return {
|
|
protocol: parser.protocol,
|
|
hostname: parser.hostname,
|
|
port: parser.port,
|
|
pathname: parser.pathname,
|
|
search: parser.search,
|
|
hash: parser.hash,
|
|
host: parser.host,
|
|
};
|
|
}
|
|
|
|
export function deleteUrlParam(key: string) {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
const url = new URL(window.location.href);
|
|
if (!url.searchParams.has(key)) {
|
|
return;
|
|
}
|
|
|
|
url.searchParams.delete(key);
|
|
window.history.pushState(null, '', url.toString());
|
|
}
|
|
|
|
export function setUrlParams(params: Record<string, string>) {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
|
|
const url = new URL(window.location.href);
|
|
let hasUpdatedUrl = false;
|
|
|
|
for (const [key, value] of Object.entries(params)) {
|
|
if (url.searchParams.get(key) === String(value)) {
|
|
continue;
|
|
}
|
|
|
|
url.searchParams.delete(key);
|
|
url.searchParams.set(key, value);
|
|
|
|
hasUpdatedUrl = true;
|
|
}
|
|
|
|
if (hasUpdatedUrl) {
|
|
window.history.pushState(null, '', url.toString());
|
|
}
|
|
}
|