What steps do I need to take to ensure the progress bar extends all the way to the end of the sn

I am currently facing a challenge where the progress bar line in my message queue does not reach the end of the message before it closes. I have included a brief video showcasing the issue along with the relevant code snippet. Any suggestions or ideas would be greatly appreciated!

Video: 1º: GenericSnackbarMessage

interface GenericSnackbarMessageProps {
  id: string;
  open: boolean;
  onClose: () => void;
  title?: string;
  message?: string;
  icon: ReactNode;
  showLinearProgress?: boolean;
  closeMessageAfterTime?: boolean;
  isLastElement?: boolean;
  activeTimer?: boolean;
}

const useProgressBarStyles = makeStyles(() =>
  createStyles({
    progressBar: {
      // Custom styling for progress bar animation
      '&[aria-valuenow="0"]': {
        '& > $progressBarInner': {
          transition: 'none',
        },
      },
    },
    progressBarInner: {},
  })
);

const SlideTransition = (props: SlideProps) => <Slide {...props} direction="left" />;

const GenericSnackbarMessage = ({
  id,
  open,
  onClose,
  title = 'Title',
  message = 'Insert message here',
  icon,
  showLinearProgress,
  closeMessageAfterTime = true,
  isLastElement,
  activeTimer = true,
}: GenericSnackbarMessageProps) => {

  const { palette } = useTheme();

  const isDark = palette.mode === 'dark';

  const handleClose = useCallback((): void => {
    onClose();
  }, [onClose]);

  const classes = useProgressBarStyles();
  const [progress, setProgress] = useState<number>(0);

  // Additional functionality to handle the progress bar animation and timer

  useEffect(() => {
    if (!closeMessageAfterTime || !activeTimer || !isLastElement) return;

    const startTime = Date.now();
    const duration = 4000;

    const updateProgress = (): void => {
      const currentTime = Date.now();
      const elapsedTime = currentTime - startTime;
      const innerProgress = elapsedTime / duration * 100;

      setProgress(innerProgress >= 100 ? 100 : innerProgress);

      if (innerProgress >= 100 && elapsedTime >= duration) {
        console.log('Progress at timer end:', innerProgress);
        handleClose();
      }
    };

    const timerId = setInterval(updateProgress, 100);

    return (): void => {
      clearInterval(timerId);
    };
  }, [closeMessageAfterTime, activeTimer, isLastElement, handleClose]);

  return (
    <Snackbar
      open={open}
      anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
      TransitionComponent={SlideTransition}
    >
      <div>
        <Alert
          sx={{
            // Styling configurations for the alert message display
          }}
          icon={!!icon && (
            <Stack
              justifyContent="center"
              alignItems="center"
              style={{
                // Customize the appearance of the icon container
              }}
            >
              {icon}
            </Stack>
          )}
          action={(
            <CrossIcon
              style={{
              // Styling for the closing icon
              }}
              onClick={handleClose}
            />
          )}
        >
          <AlertTitle sx={{ paddingTop: 8 }}>
            <Typography variant='headings.h4' color={isDark ? '#FFFFFF' : '#222221B2'}>{title}</Typography>
          </AlertTitle>
          <Typography variant='captions.default' color={isDark ? '#FFFFFF' : '#222221B2'}>{message}</Typography>
        </Alert>
        {showLinearProgress
          && (
            <LinearProgress
              variant="determinate"
              className={classes.progressBar}
              value={progress}
              classes={{ bar: classes.progressBarInner }}
            />
          )}
      </div>
    </Snackbar>
  );
};

export default GenericSnackbarMessage;
export type { GenericSnackbarMessageProps };
interface SnackbarProviderProps{
  children: React.ReactNode;
}

2º Provider

export const SnackbarProvider = ({ children }: SnackbarProviderProps): ReactElement => {

  // State management for the snackbar queue
  const [snackbarQueue, setSnackbarQueue] = useState<Array<GenericSnackbarMessageProps>>([]);

  // Add a new snackbar message to the queue
  const addSnackbar = useCallback(
    (snackbarConfig: GenericSnackbarMessageProps): void => {
      setSnackbarQueue((prev) => [...prev, snackbarConfig]);
    },
    []
  );

  // Remove a specific snackbar from the queue
  const removeSnackbar = (id: string): void => {
    setSnackbarQueue((prev) => prev.filter((snackbar) => snackbar.id !== id));
  };

  // Context value for managing snackbar messages
  const contextValue: SnackbarContextType = useMemo(() => ({
    showGenericMessage: (snackbarConfig: GenericSnackbarMessageProps): void => {
      addSnackbar(snackbarConfig);
    },
    clearAllSnackbars:  (): void => {
      setSnackbarQueue([]);
    },
  }), [addSnackbar]);

  return (
    <SnackbarContext.Provider value={contextValue}>
      {children}
      {snackbarQueue.length > 0
        && snackbarQueue.map((snackbar, index) => (
          <GenericSnackbarMessage
            key={snackbar.id}
            {...snackbar}
            title={`I'm number ${index}`}
            isLastElement={snackbarQueue.length - 1 === index}
            onClose={(): void => void removeSnackbar(snackbar.id)}
          />
      ))}

    </SnackbarContext.Provider>
  );
};

Answer №1

mariadev It appears that there is a slight delay in the css-transition on the LinearProgress component.

.css-8n2xj1-MuiLinearProgress-bar1 {
    width: 100%;
    position: absolute;
    left: 0;
    bottom: 0;
    top: 0;
    -webkit-transition: -webkit-transform .4s linear;
    transition: transform .4s linear;
    transform-origin: left;
    background-color: #2065D1;
}

For instance, when transitioning from a progress value of 40 to 60, the change won't occur instantly. There is a 400ms delay before reaching the target value. To address this, you can modify the code as shown below.

  • GenericSnackBarMessage
const timerId = setInterval(() => {
  const currentTime = Date.now();
  const elapsedTime = currentTime - startTime;
  const innerProgress = elapsedTime / duration * 100;

  setProgress(innerProgress >= 100 ? 100 : innerProgress);

  if (innerProgress >= 110 && elapsedTime >= duration) {
    console.log('Progress at timer end:', innerProgress);
    handleClose();
  }
}, 100);

I have adjusted the comparison value to 110, because the total required duration = 4000ms + 400ms = 4400ms (110%)

if (innerProgress >= 110 && elapsedTime >= duration) {
        console.log('Progress at timer end:', innerProgress);
        handleClose();
}

I trust that this response will be beneficial for your situation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Live Search: Find Your Answers with Ajax

I've come across this issue multiple times, but haven't found a solution that fits my specific requirements. I've encountered several URLs with links like example.com/ajax/search?query=Thing I'm currently working on a header and using ...

struggling with responseText functionality in javascript

I am encountering an issue with passing variables from PHP to JavaScript using JSON. The problem lies in the fact that I am able to debug and view the items in the responseText within my JavaScript, but I am unable to assign them to a variable or properly ...

What causes the unexpected "JSX tag's 'children' prop only expects one child" error when using a component that can accept multiple children?

When using the <DialogContent>, it can accept multiple children as shown in this example. The issue arises here: <DialogContent dividers> {loading && <Stack alignItems='center'> <CircularProgress /> ...

Vuetify's v-list-item no longer has spacing issues when using the v-slot:prepend feature

Currently, I am in the process of designing a side navigation using v-navigation-drawer. While most of my items utilize an icon, I also want to create some custom behaviors. Unfortunately, the title in v-slot:title does not align with the title in the v- ...

Displaying a loading progress bar while the website is being loaded using Javascript

Currently working on developing a GUI site, I am looking to implement a progress bar. However, I require some JavaScript code that can detect the loading status of the site along with the number of elements/images that have been loaded so far, as well as d ...

The capability to scroll within a stationary container

Whenever you click a button, a div slides out from the left by 100%. This div contains the menu for my website. The problem I'm encountering is that on smaller browser sizes, some of the links are hidden because they get covered up. The #slidingMenu ...

Efficiently update numerous users simultaneously within Firebase

I am trying to figure out how to update multiple user objects stored in my Firebase 2.x DB simultaneously. Each object is structured similarly to the following example: { "users": { "$id": { "date_of_birth": "June 23, 1912", "full_name": ...

Get all the classes from the body element of the AJAX-loaded page and update the body classes on the current page with them

I am currently in the process of AJAX-ing a WordPress theme with a persistent music player. In Wordpress, dynamic classes are used on the <body> tag. The structure I'm working with looks like this: <html> <head> </head> ...

What is the best way to use two distinct CSS styles for mat-form-field across multiple pages?

On one of my pages, I have a mat-form-field: <mat-form-field class="form-control-full-width"> <input type="text" matInput placeholder="First Name" formControlName="firstNameFC" required> <mat-error *ngIf="hasNewUserErro ...

Submitting a form via NextJS to an internal API

After reading through the Next.JS documentation, I came across an interesting point. Note: Instead of using fetch() to call an API route in getStaticProps, it's recommended to directly import the logic from within your API route and make necessary cod ...

Fill your HTML form effortlessly using data from Google Sheets

I am relatively new to this topic, but I'm seeking a solution to populate an Apps Script Web App HTML dropdown form with names directly from a Google Spreadsheet. At the moment, I've managed to retrieve an array of names from column A in my sprea ...

Improving React Components with Material-UI Integration

Is it possible to export a class extended from React.Component while using React and Material-UI? I need to access React variables like state within the class. If exporting the extended class is not an option, how can I still utilize state? Here is a samp ...

Creating a dynamic form field using JavaScript

I'm struggling with a JavaScript issue that requires some assistance. I have a form sending an exact number of inputs to be filled to a PHP file, and now I want to create a preview using jQuery or JavaScript. The challenge lies in dynamically capturin ...

Bootstrap scrollspy feature experiencing malfunction

I am encountering an issue with scrollspy on Bootstrap version 5.1. Despite following the examples in the documentation (links provided below), I am unable to make it work; there are no visible changes when scrolling. My goal is for the corresponding link ...

There was an issue locating a declaration file for the module 'clarifai'

https://i.stack.imgur.com/PgfqO.jpg I recently encountered a problem after installing the Clarifai API for a face recognition project. Despite my efforts, I have been unable to find a solution. When I hover over "import clarifai," I receive the message: ...

JS URL verification: ensuring valid URLs with JavaScript

Is it possible to combine two scripts that perform separate actions, one clicking a button and opening a new window, and the other interacting with elements in that new window simultaneously? function run() { var confirmBtn = document.querySelector(".sele ...

Sending back numerous information in the catch block

Recently, I was testing out the fetch API and encountered an issue with logging a fetch error. I tried catching the error and logging it within the catch block. Strangely, even when I added additional console.log statements in the catch block, they would ...

Ways to automatically run Java script again when new elements are included in the document model

Recently, I added paging and filtering to a page displaying a list of products. @model ProductFiltersViewModel ... <div class="row"> <aside class="col-3"> <nav class="sidebar card py-2 mb-4"> ...

Create dynamic elements in Vue.js components based on an object

I'm currently working on a component that will display elements within VueJs virtual dom using Vuex state. However, I have encountered an error that I am unable to comprehend and resolve: Avoid using observed data object as vnode data: {"class":"b ...

Error: Trying to use 'search' before it has been initialized causes a ReferenceError

Every time I run my code, I encounter this reference error but I can't figure out what's causing it. ReferenceError: Cannot access 'search' before initialization App C:/Users/GS66/Desktop/IN20/IFN666/week4/src/App.js:60 57 | 58 | expor ...