Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SST-82-OnCourse-localization-and-custom-logo_rebased #1346

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
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
46 changes: 46 additions & 0 deletions .idea/i18nally.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 22 additions & 15 deletions client-html/src/js/common/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,24 @@
* Common actions of App
* */

import { PermissionRequest, PreferenceEnum, User, UserPreference } from "@api/model";
import { ShowConfirmCaller } from "ish-ui";
import { LoginState } from "../../containers/login/reducers/state";
import { QueuedAction } from "../../model/common/ActionsQueue";
import { ApiMethods } from "../../model/common/apiHandlers";
import { AppMessage } from "../../model/common/Message";
import { _toRequestType, FULFILLED, REJECTED } from "./ActionUtils";
import { IAction } from "./IshAction";
import { PermissionRequest, PreferenceEnum, User, UserPreference } from '@api/model';
import { ShowConfirmCaller } from 'ish-ui';
import { LoginState } from '../../containers/login/reducers/state';
import { QueuedAction } from '../../model/common/ActionsQueue';
import { ApiMethods } from '../../model/common/apiHandlers';
import { AppMessage } from '../../model/common/Message';
import { _toRequestType, FULFILLED, REJECTED } from './ActionUtils';
import { IAction } from './IshAction';

export const CHECK_PERMISSIONS_REQUEST = _toRequestType("post/access");
export const CHECK_PERMISSIONS_REQUEST_FULFILLED = FULFILLED(CHECK_PERMISSIONS_REQUEST);

export const INTERRUPT_PROCESS = _toRequestType("delete/control");
export const INTERRUPT_PROCESS_FULFILLED = FULFILLED(INTERRUPT_PROCESS);

export const GET_LOGO = _toRequestType("get/preferences/logo");
export const GET_LOGO_FULFILLED = FULFILLED(GET_LOGO);

export const GET_SCRIPTS_REQUEST = _toRequestType("get/entity/scripts");
export const GET_SCRIPTS_FULFILLED = FULFILLED(GET_SCRIPTS_REQUEST);

Expand Down Expand Up @@ -103,7 +106,7 @@ interface RemoveQueuedActionMeta {

export const removeActionsFromQueue = (meta: RemoveQueuedActionMeta[]) => ({
type: REMOVE_ACTIONS_FROM_QUEUE,
payload: {meta}
payload: { meta }
});

export const executeActionsQueue = () => ({
Expand Down Expand Up @@ -146,7 +149,7 @@ export const closeDrawer = () => ({

export const getScripts = (entity: string) => ({
type: GET_SCRIPTS_REQUEST,
payload: {entity}
payload: { entity }
});

export const getOnDemandScripts = () => ({
Expand All @@ -155,7 +158,7 @@ export const getOnDemandScripts = () => ({

export const getEmailTemplatesWithKeyCode = (entities: string[]) => ({
type: GET_EMAIL_TEMPLATES_WITH_KEYCODE,
payload: {entities}
payload: { entities }
});

export const getLdapConnection = (host: string, port: string, isSsl: string, baseDn: string, user: string) => ({
Expand All @@ -167,7 +170,7 @@ export const getLdapConnection = (host: string, port: string, isSsl: string, bas

export const getMessageQueued = (type: string) => ({
type: GET_MESSAGE_QUEUED_REQUEST,
payload: {type}
payload: { type }
});

export const clearFetch = () => ({
Expand All @@ -176,12 +179,12 @@ export const clearFetch = () => ({

export const getProcessStatus = (processId: string, actions: any[]) => ({
type: START_PROCESS,
payload: {processId, actions}
payload: { processId, actions }
});

export const interruptProcess = (processId: string) => ({
type: INTERRUPT_PROCESS,
payload: {processId}
payload: { processId }
});

export const clearProcess = () => ({
Expand All @@ -190,7 +193,11 @@ export const clearProcess = () => ({

export const checkPermissions = (permissionRequest: PermissionRequest, onComplete?: IAction[]) => ({
type: CHECK_PERMISSIONS_REQUEST,
payload: {permissionRequest, onComplete}
payload: { permissionRequest, onComplete }
});

export const getLogo = () => ({
type: GET_LOGO
});

export const getUserPreferences = (keys: PreferenceEnum[]) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Paper from '@mui/material/Paper';
import Tooltip from '@mui/material/Tooltip';
import $t from '@t';
import clsx from 'clsx';
import { DD_MMM_YYYY_AT_HH_MM_A_SPECIAL, formatRelativeDate } from 'ish-ui';
import React from 'react';
import FormField from '../../formFields/FormField';

Expand Down Expand Up @@ -45,7 +46,9 @@ const NoteItem = (props: Props) => {
<Grid item>
{item.created && (
<Typography className={classes.dateInfo}>
{$t('created2')}
{$t('Created')}
{' '}
{formatRelativeDate(new Date(item.created), new Date(), DD_MMM_YYYY_AT_HH_MM_A_SPECIAL)}
</Typography>
)}
{item.createdBy && (
Expand All @@ -57,7 +60,7 @@ const NoteItem = (props: Props) => {
)}
{item.modified && (
<Typography className={clsx(classes.dateInfo, "mt-1")}>
{$t('modified')}
{$t('modified', [formatRelativeDate(new Date(item.modified), new Date(), DD_MMM_YYYY_AT_HH_MM_A_SPECIAL)])}
</Typography>
)}
{item.modifiedBy && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const NotesRenderer = props => {
<>
<span className={classes.showMore}>
<Button onClick={handleShowMore} color="primary">
{$t('show')}
{$t('show', [showMore ? $t("less") : $t("more")])}
</Button>
</span>
</>
Expand Down
42 changes: 34 additions & 8 deletions client-html/src/js/common/components/layout/Logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,50 @@
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
*/

import React, { SVGProps, useContext } from "react";
import IshOncourseLogoBlack from '../../../../images/IshOncourseLogoBlack.svg';
import IshOncourseLogoColour from '../../../../images/IshOncourseLogoColour.svg';
import IshOncourseLogoWhite from '../../../../images/IshOncourseLogoWhite.svg';
import React, { SVGProps, useContext, useEffect, useState } from 'react';
import IshLogoBlack from '../../../../images/IshLogoBlack.svg';
import IshLogoBlue from '../../../../images/IshLogoBlue.svg';
import IshLogoWhite from '../../../../images/IshLogoWhite.svg';
import { ThemeContext } from "../../../containers/ThemeContext";
import IshOncourseLogoBlack from '../../../../images/IshOncourseLogoBlack.svg';
import IshOncourseLogoColour from '../../../../images/IshOncourseLogoColour.svg';
import IshOncourseLogoWhite from '../../../../images/IshOncourseLogoWhite.svg';
import { ThemeContext } from '../../../containers/ThemeContext';
import { useAppSelector } from '../../utils/hooks';

export default ({ whiteBackgound, small, className }: SVGProps<any> & { whiteBackgound?: boolean, small?: boolean, className?: string }) => {
const themeC = useContext(ThemeContext);

let src = small ? IshLogoBlack : IshOncourseLogoBlack;
const [logos, setLogos] = useState({
IshOncourseLogoBlack,
IshOncourseLogoColour,
IshOncourseLogoWhite,
IshLogoBlack,
IshLogoBlue,
IshLogoWhite,
});

const logoPreferences = useAppSelector(state => state.preferences.logo);

useEffect(() => {
if (logoPreferences) {
setLogos({
IshOncourseLogoBlack: logoPreferences.customLogoBlack,
IshOncourseLogoColour: logoPreferences.customLogoColour,
IshOncourseLogoWhite: logoPreferences.customLogoWhite,
IshLogoBlack: logoPreferences.customLogoBlackSmall,
IshLogoBlue: logoPreferences.customLogoColourSmall,
IshLogoWhite: logoPreferences.customLogoWhiteSmall
});
}

}, [logoPreferences]);

let src = small ? logos.IshLogoBlack : logos.IshOncourseLogoBlack;

if (themeC.themeName === 'dark') {
src = small ? IshLogoWhite : IshOncourseLogoWhite;
src = small ? logos.IshLogoWhite : logos.IshOncourseLogoWhite;
} else if (whiteBackgound && themeC.themeName === 'default') {
src = small ? IshLogoBlue : IshOncourseLogoColour;
src = small ? logos.IshLogoBlue : logos.IshOncourseLogoColour;
}

return <img className={className} src={src} height={50} width={small ? 50 : 200} alt="IshOncourseLogo" />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ const CatalogWithSearch = React.memo<Props>((
item={i}
onOpen={() => toggleInstall(i)}
key={i.id}
secondaryAction={i.installed && <Typography variant="caption">{$t('added')}</Typography>}
secondaryAction={i.installed && <Typography variant="caption">{$t('Added')}</Typography>}
disabled={i.installed}
/>
))}
Expand All @@ -236,7 +236,7 @@ const CatalogWithSearch = React.memo<Props>((
item={i}
onOpen={() => toggleInstall(i)}
key={i.id}
secondaryAction={i.installed && <Typography variant="caption">{$t('added')}</Typography>}
secondaryAction={i.installed && <Typography variant="caption">{$t('Added')}</Typography>}
disabled={i.installed}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ const BottomAppBar = (
root: "listItemPadding"
}}
>
{$t('find_related_to_record')}
{$t('find_related_to_record',[selection.length])}
{selection.length > 1 ? "s" : ""}
</MenuItem>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const CreateCertificateMenu: React.FC<CreateCertificateMenuProps> = ({
<li>
<Typography variant="body2" className="pb-2">
{enrolments.withCertificate.length}
{$t('enrolment_already_have_certificates_linked_to_thei')}
{$t('enrolment_already_have_certificates_linked_to_thei', [enrolments.withCertificate.length !== 1 ? "s" : ""])}
</Typography>
</li>
) : null),
Expand All @@ -188,7 +188,7 @@ const CreateCertificateMenu: React.FC<CreateCertificateMenuProps> = ({
<li>
<Typography variant="body2" className="pb-2">
{createdCertificatesCount}
{$t('new_certificate_will_be_created')}
{$t('new_certificate_will_be_created', [createdCertificatesCount > 1 ? "s" : ""])}
</Typography>
</li>
) : null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,8 @@ class ShareForm extends React.PureComponent<Props, ShareState> {
<MenuItem className="relative w-100" key="upload" onClick={this.handleUploadBackgroundClick}>
<div className="heading centeredFlex">
<Publish/>
{$t('ml1')}
{' '}
<span className="ml-1">{$t('Upload from disk')}</span>
</div>
</MenuItem>
),
Expand Down
25 changes: 25 additions & 0 deletions client-html/src/js/common/epics/EpicGetLogoPreferences.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright ish group pty ltd 2025.
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
*/

import { Epic } from 'redux-observable';
import PreferencesService from '../../containers/preferences/services/PreferencesService';
import { GET_LOGO, GET_LOGO_FULFILLED } from '../actions';
import * as EpicUtils from './EpicUtils';

const request: EpicUtils.Request = {
type: GET_LOGO,
getData: () => PreferencesService.getLogo(),
processData: logo => [
{
type: GET_LOGO_FULFILLED,
payload: logo
}
]
};

export const EpicGetLogoPreferences: Epic<any, any> = EpicUtils.Create(request);
22 changes: 12 additions & 10 deletions client-html/src/js/common/epics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
* No copying or use of this code is allowed without permission in writing from ish.
*/

import { combineEpics } from "redux-observable";
import { EpicCheckPermission } from "./EpicCheckPermission";
import { EpicExecuteActionsQueue } from "./EpicExecuteActionsQueue";
import { EpicGetCommonPlainRecords } from "./EpicGetCommonPlainRecords";
import { EpicGetEmailTemplatesWithKeyCode } from "./EpicGetEmailTemplatesWithKeyCode";
import { EpicGetScripts } from "./EpicGetScripts";
import { EpicGetUserPreferences } from "./EpicGetUserPreferences";
import { EpicInterruptProcess } from "./EpicInterruptProcess";
import { EpicManageProcess } from "./EpicManageProcess";
import { EpicSetUserPreference } from "./EpicSetUserPreference";
import { combineEpics } from 'redux-observable';
import { EpicCheckPermission } from './EpicCheckPermission';
import { EpicExecuteActionsQueue } from './EpicExecuteActionsQueue';
import { EpicGetCommonPlainRecords } from './EpicGetCommonPlainRecords';
import { EpicGetEmailTemplatesWithKeyCode } from './EpicGetEmailTemplatesWithKeyCode';
import { EpicGetLogoPreferences } from './EpicGetLogoPreferences';
import { EpicGetScripts } from './EpicGetScripts';
import { EpicGetUserPreferences } from './EpicGetUserPreferences';
import { EpicInterruptProcess } from './EpicInterruptProcess';
import { EpicManageProcess } from './EpicManageProcess';
import { EpicSetUserPreference } from './EpicSetUserPreference';

export const EpicCommon = combineEpics(
EpicGetScripts,
Expand All @@ -22,6 +23,7 @@ export const EpicCommon = combineEpics(
EpicSetUserPreference,
EpicGetUserPreferences,
EpicExecuteActionsQueue,
EpicGetLogoPreferences,
EpicGetCommonPlainRecords,
EpicGetEmailTemplatesWithKeyCode,
);
Loading
Loading