Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/src/js/v3/@types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ declare global {
enable_individual_tax_control: boolean;
is_tax_included_in_price: boolean;
pagination_per_page: string;
quiz_attempts_allowed: string;
};
tutor_currency: {
symbol: string;
Expand Down
11 changes: 7 additions & 4 deletions assets/src/js/v3/entries/addon-list/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Global } from '@emotion/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import ToastProvider from '@TutorShared/atoms/Toast';
import RTLProvider from '@TutorShared/components/RTLProvider';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';
import { createGlobalCss } from '@TutorShared/utils/style-utils';
import { useState } from 'react';
import Main from './layout/Main';
Expand All @@ -27,10 +28,12 @@ function App() {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-center">
<Global styles={createGlobalCss()} />
<Main />
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-center">
<Global styles={createGlobalCss()} />
<Main />
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
15 changes: 9 additions & 6 deletions assets/src/js/v3/entries/coupon-details/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import ToastProvider from '@TutorShared/atoms/Toast';
import { ModalProvider } from '@TutorShared/components/modals/Modal';
import RTLProvider from '@TutorShared/components/RTLProvider';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';
import { createGlobalCss } from '@TutorShared/utils/style-utils';
import { useState } from 'react';
import Main from './layout/Main';
Expand All @@ -27,12 +28,14 @@ function App() {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-center">
<ModalProvider>
<Global styles={createGlobalCss()} />
<Main />
</ModalProvider>
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-center">
<ModalProvider>
<Global styles={createGlobalCss()} />
<Main />
</ModalProvider>
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
19 changes: 11 additions & 8 deletions assets/src/js/v3/entries/course-builder/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CourseBuilderSlotProvider } from '@CourseBuilderContexts/CourseBuilderS
import ToastProvider from '@TutorShared/atoms/Toast';
import RTLProvider from '@TutorShared/components/RTLProvider';
import { ModalProvider } from '@TutorShared/components/modals/Modal';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';
import { createGlobalCss } from '@TutorShared/utils/style-utils';
import { Global } from '@emotion/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
Expand Down Expand Up @@ -32,14 +33,16 @@ const App = () => {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-center">
<CourseBuilderSlotProvider>
<ModalProvider>
<Global styles={createGlobalCss()} />
{routers}
</ModalProvider>
</CourseBuilderSlotProvider>
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-center">
<CourseBuilderSlotProvider>
<ModalProvider>
<Global styles={createGlobalCss()} />
{routers}
</ModalProvider>
</CourseBuilderSlotProvider>
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { POPOVER_PLACEMENTS } from '@TutorShared/hooks/usePortalPopover';
import { validateQuizQuestion } from '@TutorShared/utils/quiz';
import { type ID, isDefined, type TopicContentType } from '@TutorShared/utils/types';
import { findSlotFields } from '@TutorShared/utils/util';
import { tutorConfig } from '@TutorShared/config/config';

interface QuizModalProps extends ModalProps {
quizId?: ID;
Expand All @@ -56,6 +57,7 @@ interface QuizModalProps extends ModalProps {
type QuizTabs = 'details' | 'settings';

const courseId = getCourseId();
const defaultQuizAttemptsAllowed = tutorConfig.settings?.quiz_attempts_allowed ?? 10;

const QuizModal = ({
closeModal,
Expand Down Expand Up @@ -89,7 +91,7 @@ const QuizModal = ({
hide_quiz_time_display: false,
limit_attempts_allowed: false,
limit_questions_to_answer: false,
attempts_allowed: 10,
attempts_allowed: defaultQuizAttemptsAllowed,
passing_grade: 80,
max_questions_for_answer: contentType === 'tutor_h5p_quiz' ? 0 : 10,
quiz_auto_start: false,
Expand Down
3 changes: 2 additions & 1 deletion assets/src/js/v3/entries/course-builder/services/quiz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ interface QuizUpdateQuestionPayload {
}

export const convertQuizResponseToFormData = (quiz: QuizDetailsResponse, slotFields: string[]): QuizForm => {
const defaultQuizAttemptsAllowed = tutorConfig.settings?.quiz_attempts_allowed ?? 10;
const legacyQuizOption = quiz.quiz_option as QuizDetailsResponse['quiz_option'] & {
feedback_mode?: 'default' | 'reveal' | 'retry';
};
Expand All @@ -182,7 +183,7 @@ export const convertQuizResponseToFormData = (quiz: QuizDetailsResponse, slotFie
limit_attempts_allowed: isDefined(quiz.quiz_option.limit_attempts_allowed)
? quiz.quiz_option.limit_attempts_allowed === '1'
: legacyQuizOption.feedback_mode === 'retry',
attempts_allowed: quiz.quiz_option.attempts_allowed ?? 10,
attempts_allowed: quiz.quiz_option.attempts_allowed ?? defaultQuizAttemptsAllowed,
pass_is_required: quiz.quiz_option.pass_is_required === '1',
passing_grade: quiz.quiz_option.passing_grade ?? 80,
limit_questions_to_answer: !!Number(quiz.quiz_option.max_questions_for_answer),
Expand Down
15 changes: 9 additions & 6 deletions assets/src/js/v3/entries/import-export/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Main from '@ImportExport/components/Main';
import ToastProvider from '@TutorShared/atoms/Toast';
import RTLProvider from '@TutorShared/components/RTLProvider';
import { ModalProvider } from '@TutorShared/components/modals/Modal';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';
import { createGlobalCss } from '@TutorShared/utils/style-utils';

function App() {
Expand All @@ -29,12 +30,14 @@ function App() {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-right">
<ModalProvider>
<Global styles={createGlobalCss()} />
<Main />
</ModalProvider>
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-right">
<ModalProvider>
<Global styles={createGlobalCss()} />
<Main />
</ModalProvider>
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
15 changes: 9 additions & 6 deletions assets/src/js/v3/entries/order-details/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ToastProvider from '@TutorShared/atoms/Toast';

import RTLProvider from '@TutorShared/components/RTLProvider';
import { ModalProvider } from '@TutorShared/components/modals/Modal';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';

import { createGlobalCss } from '@TutorShared/utils/style-utils';
import Main from './layout/Main';
Expand All @@ -30,12 +31,14 @@ function App() {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-right">
<ModalProvider>
<Global styles={createGlobalCss()} />
<Main />
</ModalProvider>
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-right">
<ModalProvider>
<Global styles={createGlobalCss()} />
<Main />
</ModalProvider>
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
19 changes: 11 additions & 8 deletions assets/src/js/v3/entries/payment-settings/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useState } from 'react';
import ToastProvider from '@TutorShared/atoms/Toast';
import RTLProvider from '@TutorShared/components/RTLProvider';
import { ModalProvider } from '@TutorShared/components/modals/Modal';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';
import { createGlobalCss } from '@TutorShared/utils/style-utils';

import { PaymentProvider } from '../contexts/payment-context';
Expand All @@ -31,14 +32,16 @@ function App() {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-right">
<PaymentProvider>
<ModalProvider>
<Global styles={createGlobalCss()} />
<PaymentSettings />
</ModalProvider>
</PaymentProvider>
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-right">
<PaymentProvider>
<ModalProvider>
<Global styles={createGlobalCss()} />
<PaymentSettings />
</ModalProvider>
</PaymentProvider>
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
15 changes: 9 additions & 6 deletions assets/src/js/v3/entries/tax-settings/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useState } from 'react';
import ToastProvider from '@TutorShared/atoms/Toast';
import RTLProvider from '@TutorShared/components/RTLProvider';
import { ModalProvider } from '@TutorShared/components/modals/Modal';
import { SVGIconConfigProvider } from '@TutorShared/contexts/SVGIconConfigContext';
import { createGlobalCss } from '@TutorShared/utils/style-utils';

import TaxSettingsPage from './TaxSettings';
Expand All @@ -30,12 +31,14 @@ function App() {
return (
<RTLProvider>
<QueryClientProvider client={queryClient}>
<ToastProvider position="bottom-right">
<ModalProvider>
<Global styles={createGlobalCss()} />
<TaxSettingsPage />
</ModalProvider>
</ToastProvider>
<SVGIconConfigProvider>
<ToastProvider position="bottom-right">
<ModalProvider>
<Global styles={createGlobalCss()} />
<TaxSettingsPage />
</ModalProvider>
</ToastProvider>
</SVGIconConfigProvider>
</QueryClientProvider>
</RTLProvider>
);
Expand Down
19 changes: 7 additions & 12 deletions assets/src/js/v3/shared/atoms/SVGIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { tutorConfig } from '@TutorShared/config/config';
import { useSVGIconConfig } from '@TutorShared/contexts/SVGIconConfigContext';
import { type IconCollection } from '@TutorShared/icons/types';
import { type SerializedStyles, css } from '@emotion/react';
import { memo, useEffect, useState } from 'react';
Expand Down Expand Up @@ -28,16 +29,10 @@ interface IconCacheEntry {

const iconCache: Record<string, IconCacheEntry> = {};

const SVGIcon = ({
name,
width = 16,
height = 16,
style,
isColorIcon = false,
ignoreKids = false,
...rest
}: SVGIconProps) => {
const cacheKey = ignoreKids ? `${name}-ignoreKids` : name;
const SVGIcon = ({ name, width = 16, height = 16, style, isColorIcon = false, ignoreKids, ...rest }: SVGIconProps) => {
const { showKidsIcons } = useSVGIconConfig();
const shouldIgnoreKids = ignoreKids ?? !showKidsIcons;
const cacheKey = shouldIgnoreKids ? `${name}-ignoreKids` : name;
const [icon, setIcon] = useState<Icon | null>(iconCache[cacheKey]?.icon || null);
const [isLoading, setIsLoading] = useState(!iconCache[cacheKey]?.icon);

Expand All @@ -50,7 +45,7 @@ const SVGIcon = ({

setIsLoading(true);

fetchIcon(name, cacheKey, width, height, ignoreKids)
fetchIcon(name, cacheKey, width, height, shouldIgnoreKids)
.then((loadedIcon) => {
setIcon(loadedIcon);
})
Expand All @@ -60,7 +55,7 @@ const SVGIcon = ({
.finally(() => {
setIsLoading(false);
});
}, [name, width, height, ignoreKids, cacheKey]);
}, [name, width, height, shouldIgnoreKids, cacheKey]);

const additionalAttributes = {
...(isColorIcon && { 'data-colorize': true }),
Expand Down
31 changes: 31 additions & 0 deletions assets/src/js/v3/shared/contexts/SVGIconConfigContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useContext } from 'react';

interface SVGIconConfigContextValue {
supportKidsIcon: boolean;
}

const defaultValue: SVGIconConfigContextValue = {
supportKidsIcon: false,
};

const SVGIconConfigContext = React.createContext<SVGIconConfigContextValue>(defaultValue);

export const useSVGIconConfig = () => useContext(SVGIconConfigContext);

export const SVGIconConfigProvider = ({
children,
supportKidsIcon = false,
}: {
children: React.ReactNode;
supportKidsIcon?: boolean;
}) => {
return (
<SVGIconConfigContext.Provider
value={{
supportKidsIcon,
}}
>
{children}
</SVGIconConfigContext.Provider>
);
};
1 change: 1 addition & 0 deletions classes/Course.php
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
global $wp_query;
$course_coming_soon_enabled = (int) get_post_meta( $content->ID, '_tutor_course_enable_coming_soon', true );
$is_instructor = tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $content->ID, true );
if ( ! CourseModel::get_post_types( $content ) || current_user_can( 'administrator' ) || $is_instructor || $course_coming_soon_enabled ) {

Check failure on line 332 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

Capabilities should be used instead of roles. Found &quot;administrator&quot; in function call to current_user_can()
return $content;
}

Expand Down Expand Up @@ -660,7 +660,7 @@
} else {
$errors['pricing'] = __( 'Invalid product', 'tutor' );
}
} else {

Check failure on line 663 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

If control structure block found as the only statement within an &quot;else&quot; block. Use elseif instead.
/**
* If user does not select WC product
* Then automatic WC product will be create name with course title.
Expand Down Expand Up @@ -797,7 +797,7 @@
update_post_meta( $post_id, self::COURSE_PRICE_TYPE_META, $params['pricing']['type'] );
}
} catch ( \Throwable $th ) {
throw new \Exception( $th->getMessage() );

Check failure on line 800 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '$th'.
}
}

Expand Down Expand Up @@ -1543,6 +1543,7 @@
'instructor_can_publish_course',
'instructor_can_change_course_author',
'instructor_can_manage_co_instructors',
'quiz_attempts_allowed',
);

$full_settings = get_option( 'tutor_option', array() );
Expand Down Expand Up @@ -2361,7 +2362,7 @@
}

// Check if user is only an instructor.
if ( ! current_user_can( 'administrator' ) ) {

Check failure on line 2365 in classes/Course.php

View workflow job for this annotation

GitHub Actions / WPCS

Capabilities should be used instead of roles. Found &quot;administrator&quot; in function call to current_user_can()
// Check if instructor can trash course.
$can_trash_post = tutor_utils()->get_option( 'instructor_can_delete_course' );

Expand Down
Loading