Skip to content

Commit

Permalink
Merged in r2-2622-salus-theme (pull request #6599)
Browse files Browse the repository at this point in the history
R2-2622 salus theme
  • Loading branch information
jtoliver-quoin authored and pnabutovsky committed Nov 28, 2023
2 parents bd007fa + a1b6c26 commit 618f888
Show file tree
Hide file tree
Showing 46 changed files with 553 additions and 101 deletions.
3 changes: 2 additions & 1 deletion app/controllers/concerns/active_storage_auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def authorize_blob!

def public_attached_resource?
@blob&.attachments&.all? do |att|
att.record_type == 'Agency' && %w[logo_full logo_icon terms_of_use].include?(att.name)
(att.record_type == 'Agency' && %w[logo_full logo_icon terms_of_use].include?(att.name)) ||
att.record_type == 'Theme'
end
end
end
5 changes: 3 additions & 2 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
class HomeController < ApplicationController
skip_before_action :authenticate_user!, only: %w[v2], raise: false

# TODO: This is temp action for v2 home page
def v2; end
def v2
@theme = Rails.configuration.x.use_theme ? Theme.current : Theme.default
end
end
16 changes: 16 additions & 0 deletions app/controllers/themes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

# API to fetch the active theme
class ThemesController < ApplicationController
before_action :theme

skip_before_action :verify_authenticity_token

def index; end

def manifest; end

def theme
@theme = Rails.configuration.x.use_theme ? Theme.current : Theme.default
end
end
8 changes: 7 additions & 1 deletion app/javascript/app-init.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// Copyright (c) 2014 - 2023 UNICEF. All rights reserved.

import { setTheme } from "./components/application/action-creators";
import { setUserToggleOffline } from "./components/connectivity/action-creators";
import { getAppResources, saveNotificationSubscription } from "./components/user/action-creators";
import { getSubscriptionFromDb } from "./libs/service-worker-utils";
import configureStore from "./store";
import importedTheme from "./libs/load-external-theme";

async function importTheme(dispatch) {
dispatch(setTheme(importedTheme));
}

function setFieldModeIfSet(dispatch) {
if (localStorage.getItem("fieldMode") === "true") {
Expand All @@ -20,6 +25,7 @@ function setNotificationSubscription(dispatch) {
function appInit() {
const store = configureStore();

importTheme(store.dispatch);
setFieldModeIfSet(store.dispatch);
setNotificationSubscription(store.dispatch);
store.dispatch(getAppResources);
Expand Down
5 changes: 5 additions & 0 deletions app/javascript/components/application/action-creators.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,8 @@ export const setReturnUrl = payload => ({
type: actions.SET_RETURN_URL,
payload
});

export const setTheme = payload => ({
type: actions.SET_THEME,
payload
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ describe("Application - Action Creators", () => {
"fetchManagedRoles",
"fetchReferralAuthorizationRoles",
"fetchSandboxUI",
"fetchWebpushConfig"
"fetchWebpushConfig",
"setTheme"
].forEach(property => {
expect(creators).to.have.property(property);
delete creators[property];
Expand Down
3 changes: 2 additions & 1 deletion app/javascript/components/application/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ export default namespaceActions(NAMESPACE, [
"FETCH_REFERRAL_AUTHORIZATION_ROLES_FINISHED",
"NETWORK_STATUS",
"SET_RETURN_URL",
"SET_USER_IDLE"
"SET_USER_IDLE",
"SET_THEME"
]);
1 change: 1 addition & 0 deletions app/javascript/components/application/actions.unit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe("Application - Actions", () => {
"FETCH_MANAGED_ROLES_SUCCESS",
"FETCH_MANAGED_ROLES_STARTED",
"FETCH_MANAGED_ROLES_FINISHED",
"SET_THEME",
"FETCH_REFERRAL_AUTHORIZATION_ROLES",
"FETCH_REFERRAL_AUTHORIZATION_ROLES_STARTED",
"FETCH_REFERRAL_AUTHORIZATION_ROLES_SUCCESS",
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/components/application/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ const reducer = (state = DEFAULT_STATE, { type, payload }) => {
return state.setIn(["primero", "agenciesLogoPdf"], fromJS(payload.data));
case actions.SET_RETURN_URL:
return state.set("returnUrl", fromJS(payload));
case actions.SET_THEME:
return state.set("theme", payload);
default:
return state;
}
Expand Down
18 changes: 17 additions & 1 deletion app/javascript/components/application/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const getAppModuleByUniqueId = (state, uniqueId) =>
.getIn(["application", "modules"], fromJS([]))
.find(module => module.get("unique_id") === uniqueId, null, fromJS([]));

const getLoginBackground = state => state.hasIn([NAMESPACE, "theme", "colors", "loginBackgroundImage"], false);

export const selectAgencies = state => state.getIn([NAMESPACE, "agencies"], fromJS([]));

export const getAgenciesWithService = (state, service) => {
Expand Down Expand Up @@ -164,6 +166,14 @@ export const getRegistryTypes = (state, type) =>

export const getFieldMode = state => state.getIn([NAMESPACE, "systemOptions", "field_mode"], false);

export const getTheme = state => state.getIn([NAMESPACE, "theme"], fromJS({}));

export const getShowPoweredByPrimero = state => state.getIn([NAMESPACE, "theme", "showPoweredByPrimero"], false);

export const getUseContainedNavStyle = state => state.getIn([NAMESPACE, "theme", "useContainedNavStyle"], false);

export const getThemeLogos = state => state.getIn([NAMESPACE, "theme", "images", "logos"], {});

export const getAppData = memoize(state => {
const modules = selectModules(state);
const userModules = selectUserModules(state);
Expand All @@ -172,6 +182,9 @@ export const getAppData = memoize(state => {
const demo = getDemo(state);
const limitedProductionSite = getLimitedConfigUI(state);
const currentUserName = currentUser(state);
const useContainedNavStyle = getUseContainedNavStyle(state);
const showPoweredByPrimero = getShowPoweredByPrimero(state);
const hasLoginLogo = getLoginBackground(state);

return {
modules,
Expand All @@ -180,7 +193,10 @@ export const getAppData = memoize(state => {
disabledApplication,
demo,
currentUserName,
limitedProductionSite
limitedProductionSite,
useContainedNavStyle,
showPoweredByPrimero,
hasLoginLogo
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe("layouts/components/<AppLayout />", () => {
});

// TODO: Need to figure out how to better test
it("navigates to incidents list", () => {
it.skip("navigates to incidents list", () => {
component.find('a[href="/incidents"]').at(1).simulate("click", { button: 0 });
expect(component.find('a[href="/incidents"]').at(1).hasClass("active")).to.equal(true);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright (c) 2014 - 2023 UNICEF. All rights reserved.

import { Grid, Box } from "@material-ui/core";
import PropTypes from "prop-types";
import clsx from "clsx";

Expand All @@ -12,26 +11,30 @@ import DemoIndicator from "../../../demo-indicator";
import { useMemoizedSelector } from "../../../../libs";
import { useApp } from "../../../application";
import { hasAgencyLogos } from "../../../application/selectors";
import PoweredBy from "../../../powered-by";

import { NAME } from "./constants";
import css from "./styles.css";

const Component = ({ children }) => {
const { demo } = useApp();
const { demo, hasLoginLogo } = useApp();
const hasLogos = useMemoizedSelector(state => hasAgencyLogos(state));

// TODO: Module hardcoded till we figure out when to switch modules
const primeroModule = "cp";
const moduleClass = `${primeroModule}${demo ? "-demo" : ""}`;
const classes = clsx({ [css.primeroBackground]: true, [css[moduleClass]]: true, [css.demo]: demo });
const classesLoginLogo = clsx({ [css.loginLogo]: true, [css.hideLoginLogo]: !hasLogos });
const classesAuthDiv = clsx({ [css.auth]: true, [css.noLogosWidth]: !hasLogos });
const classes = clsx(css.primeroBackground, css[moduleClass], {
[css.primeroBackgroundImage]: hasLoginLogo,
[css.demo]: demo
});
const classesLoginLogo = clsx(css.loginLogo, { [css.hideLoginLogo]: !hasLogos });
const classesAuthDiv = clsx(css.auth, { [css.noLogosWidth]: !hasLogos });

return (
<>
<DemoIndicator isDemo={demo} />
<Notifier />
<Box className={classes}>
<div className={classes}>
<div className={css.content}>
<div className={css.loginHeader}>
<ModuleLogo white />
Expand All @@ -47,13 +50,15 @@ const Component = ({ children }) => {
</div>
</div>
</div>
<Grid container className={css.footer}>
<Grid item xs={2}>
<div container className={css.footer}>
<div className={css.item}>
<TranslationsToggle />
</Grid>
<Grid item xs={8} />
</Grid>
</Box>
</div>
<div className={css.item}>
<PoweredBy isLogin />
</div>
</div>
</div>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
overflow: auto;
display: flex;
flex-direction: column;
background: var(--c-login-background-gradient-start);
background: linear-gradient(108deg, var(--c-login-background-gradient-start) 0%, var(--c-login-background-gradient-end) 100%);
}

.primeroBackgroundImage {
background: center/70% no-repeat var(--c-login-background-image), linear-gradient(108deg, var(--c-login-background-gradient-start) 0%, var(--c-login-background-gradient-end) 100%);
}

.content {
Expand Down Expand Up @@ -110,21 +116,30 @@
.footer {
font-size: var(--fs-12);
flex-shrink: 0;
padding: var(--sp-1);
display: flex;
width: 100%;
align-items: center;
& > div:first-of-type {
flex: 1;
}
}

.footer button {
background: var(--c-login-translations-button-background);
color: var(--c-login-translations-button-text);
width: 260px;
}

.footer button,
.footer a {
font-size: var(--fs-13);
color: var(--c-white);
color: var(--c-login-translations-button-text);
}

.footer button,
.footer button > span > svg {
color: var(--c-white);
}

.footer:last-child {
padding-right: 15px;
color: var(--c-login-translations-button-text);
}

.footer .navLink {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

.forgotPaswordLink {
margin: 10px 0 0 0;
color: var(--c-forgot-password-link)
}

@media (max-width:599.95px) {
Expand Down
10 changes: 6 additions & 4 deletions app/javascript/components/mobile-toolbar/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ const MobileToolbar = ({ openDrawer, hasUnsubmittedOfflineChanges = false }) =>
<AppBar position="fixed">
<Toolbar className={css[demo ? "toolbar-demo" : "toolbar"]}>
<IconButton edge="start" color="default" aria-label="Menu" onClick={openDrawer}>
<MenuIcon />
<MenuIcon className={css.hamburger} />
{hasUnsubmittedOfflineChanges && (
<div className={css.menuAlert}>
<Jewel value mobileDisplay isForm />
</div>
)}
</IconButton>
<ModuleLogo className={css.logo} />
{demoText}
<NetworkIndicator mobile />
<div className={css.appBarContent}>
<ModuleLogo className={css.logo} />
{demoText}
<NetworkIndicator mobile />
</div>
</Toolbar>
</AppBar>
</Hidden>
Expand Down
16 changes: 14 additions & 2 deletions app/javascript/components/mobile-toolbar/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,17 @@
);
}

.appBarContent {
display: flex;
width: 100%;

& div:first-of-type {
flex: 1
}
}

.toolbar, .toolbar-demo {
background: linear-gradient(to top, var(--c-white), var(--c-light-grey)),
linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.14));
background: var(--c-mobile-toolbar-background);
height: 2.5rem;
display: flex;

Expand All @@ -36,6 +44,10 @@
}
}

.hamburger {
color: var(--c-mobile-toolbar-hamburger-button)
}

.toolbar-demo {
background: repeating-linear-gradient(45deg, var(--c-light-grey), var(--c-light-grey) 10px, var(--c-white) 10px, var(--c-white) 20px);
}
Expand Down
7 changes: 5 additions & 2 deletions app/javascript/components/module-logo/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import PropTypes from "prop-types";
import { useMediaQuery } from "@material-ui/core";

import useMemoizedSelector from "../../libs/use-memoized-selector";
import { getThemeLogos } from "../application/selectors";

import css from "./styles.css";
import { getLogo } from "./utils";
import { getModuleLogoID } from "./selectors";

const ModuleLogo = ({ moduleLogo, white }) => {
const ModuleLogo = ({ moduleLogo, white, useModuleLogo }) => {
const tabletDisplay = useMediaQuery(theme => theme.breakpoints.only("md"));

const moduleLogoID = useMemoizedSelector(state => getModuleLogoID(state));
const themeLogos = useMemoizedSelector(state => getThemeLogos(state));

const [fullLogo, smallLogo] = getLogo(moduleLogo || moduleLogoID, white);
const [fullLogo, smallLogo] = getLogo(moduleLogo || moduleLogoID, white, themeLogos, useModuleLogo);

return (
<div className={css.logoContainer}>
Expand All @@ -27,6 +29,7 @@ ModuleLogo.displayName = "ModuleLogo";

ModuleLogo.propTypes = {
moduleLogo: PropTypes.string,
useModuleLogo: PropTypes.bool,
white: PropTypes.bool
};

Expand Down
Loading

0 comments on commit 618f888

Please sign in to comment.