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

[TM-1531] add job connection #745

Draft
wants to merge 1 commit into
base: feat/TM-1531-add-job-service
Choose a base branch
from
Draft
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: 26 additions & 20 deletions src/components/elements/Notification/FloatNotification.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import classNames from "classnames";
import { useState } from "react";
import { useEffect, useState } from "react";
import { When } from "react-if";

import Icon, { IconNames } from "@/components/extensive/Icon/Icon";
import { useDelayedJobs } from "@/connections/DelayedJob";

import LinearProgressBar from "../ProgressBar/LinearProgressBar/LinearProgressBar";
import Text from "../Text/Text";

export interface FloatNotificationDataProps {
Expand All @@ -17,9 +17,13 @@ export interface FloatNotificationProps {
data: FloatNotificationDataProps[];
}

const FloatNotification = ({ data }: FloatNotificationProps) => {
const FloatNotification = () => {
const [openModalNotification, setOpenModalNotification] = useState(false);
const [isLoaded, { delayedJobs }] = useDelayedJobs();

useEffect(() => {
console.log("delayedJobs", delayedJobs);
}, [isLoaded, delayedJobs]);
return (
<div className="fixed bottom-10 right-10 z-50">
<div className="relative">
Expand All @@ -43,31 +47,33 @@ const FloatNotification = ({ data }: FloatNotificationProps) => {
</Text>
</div>
<div className="-mr-2 flex flex-1 flex-col gap-3 overflow-auto pr-2">
{data.map((item, index) => (
<div key={index} className="rounded-lg border-2 border-grey-350 bg-white p-4 hover:border-primary">
<div className="mb-2 flex items-center gap-1">
<div className="h-2 w-2 rounded-full bg-primary" />
<Text variant="text-14-light" className="leading-[normal] text-darkCustom " as={"span"}>
{item.label}
</Text>
</div>
<Text variant="text-14-light" className="text-darkCustom">
{isLoaded &&
delayedJobs &&
delayedJobs.map((item, index) => (
<div key={index} className="rounded-lg border-2 border-grey-350 bg-white p-4 hover:border-primary">
<div className="mb-2 flex items-center gap-1">
<div className="h-2 w-2 rounded-full bg-primary" />
<Text variant="text-14-light" className="leading-[normal] text-darkCustom " as={"span"}>
{item.processedContent}
</Text>
</div>
{/* <Text variant="text-14-light" className="text-darkCustom">
Site: <b>{item.site}</b>
</Text>
<div className="mt-2 flex items-center gap-2">
</Text>*/}
{/* <div className="mt-2 flex items-center gap-2">
<LinearProgressBar value={parseInt(item.value)} className="h-2 bg-success-40" color="success-600" />
<Text variant="text-12-semibold" className="text-black">
{item.value}
</Text>
</div> */}
</div>
</div>
))}
))}
</div>
</div>
</div>
<When condition={data.length > 0}>
<When condition={isLoaded && (delayedJobs ?? []).length > 0}>
<div className="text-14-bold absolute right-[-5px] top-[-5px] z-20 flex min-h-[24px] min-w-[24px] items-center justify-center rounded-full bg-red-300 leading-[normal] text-white">
{data.length}
{delayedJobs?.length}
</div>
</When>
<button
Expand All @@ -77,8 +83,8 @@ const FloatNotification = ({ data }: FloatNotificationProps) => {
className={classNames(
"z-10 flex h-15 w-15 items-center justify-center rounded-full border border-grey-950 bg-primary duration-300 hover:scale-105",
{
hidden: data.length < 1,
visible: data.length > 0
// hidden: (delayedJobs?.length ?? 0) < 1 && isLoaded,
// visible: (delayedJobs?.length ?? 0) > 0 && isLoaded
}
)}
>
Expand Down
57 changes: 57 additions & 0 deletions src/connections/DelayedJob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createSelector } from "reselect";

import { DelayedJobsFindVariables, listDelayedJobs } from "@/generated/v3/jobService/jobServiceComponents";
import { delayedJobsFindFetchFailed } from "@/generated/v3/jobService/jobServicePredicates";
import { DelayedJobDto } from "@/generated/v3/jobService/jobServiceSchemas";
import { ApiDataStore } from "@/store/apiSlice";
import { Connection } from "@/types/connection";
import { connectionHook } from "@/utils/connectionShortcuts";
import { selectorCache } from "@/utils/selectorCache";

type DelayedJobsConnection = {
delayedJobs?: DelayedJobDto[];
isLoading: boolean;
hasLoadFailed: boolean;
};

type DelayedJobsProps = { uuid: string };

const delayedJobsSelector = (store: ApiDataStore) => {
const delayedJobsMap = store.delayedJobs || {};
return Object.values(delayedJobsMap).map(resource => resource.attributes);
};

const delayedJobsLoadFailedSelector = (store: ApiDataStore, { uuid }: DelayedJobsProps) => {
const variables: DelayedJobsFindVariables = {
pathParams: { uuid }
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the API request doesn't use these path params, the load failed selector shouldn't either. The params to those two must always match for this feature to function.


return delayedJobsFindFetchFailed(variables)(store) != null;
};
const connectionIsLoaded = ({ delayedJobs, hasLoadFailed, isLoading }: DelayedJobsConnection) => {
return (delayedJobs != null && delayedJobs.length > 0) || hasLoadFailed || isLoading;
};

const delayedJobsConnection: Connection<DelayedJobsConnection, DelayedJobsProps> = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These props aren't used, no reason to include them.

load: (connection, props) => {
const isLoaded = connectionIsLoaded(connection);
if (!isLoaded) {
listDelayedJobs();
}
},
isLoaded: connectionIsLoaded,
selector: selectorCache(
props => props.uuid,
props =>
createSelector(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there are no props, the selector cache isn't needed - it's only needed when there are props to differentiate different selectors. The selector here can just receive createSelector

[delayedJobsSelector, store => delayedJobsLoadFailedSelector(store, props)],
(delayedJobs, hasLoadFailed): DelayedJobsConnection => ({
delayedJobs,
isLoading: delayedJobs == null && !hasLoadFailed,
hasLoadFailed
})
)
)
};

export const useDelayedJobs = connectionHook(delayedJobsConnection);
2 changes: 1 addition & 1 deletion src/context/floatNotification.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const FloatNotificationProvider = ({ children }: FloatNotificationProviderProps)
return (
<FloatNotificationContext.Provider value={value}>
{children}
<FloatNotification data={data} />
<FloatNotification />
</FloatNotificationContext.Provider>
);
};
Expand Down