Can’t find next highest value in array

// winninCombinationsState is an array of 9 integers ranging from 0 to 3.
// Game.winningCombinations is an array of 8 arrays containing 3 integers each ranging from 0 to 8.
// Game.state is an array of 9 strings. It keeps the record of the 2 player's position on the board. 

function bestMove () {
    let index; 
    while (index == undefined) {
        // Find index of first Math.max(...array) 
        let max = winningCombinationsState.indexOf(Math.max(...winningCombinationsState));
        // Check for the first empty slot within Game.state at indexes Game.winningCombinations[max]
        for (let slot in Game.winningCombinations[max]) {
            if (Game.state[slot] == "") {
                index = slot;
                break;
            }  
        }
        // Remove the best array if no empty slot were found.
        if (index == undefined) {
            delete winningCombinationsState[c];
        }
        // While Game.sate[index] is undefined. Keep searching. 
    }
    return index;
}

It works well but sometimes it gets stuck.

When index’s left undefined I have this error Game.winningCombinations[max] is not iterable

Tried using a for ... in which lift the error message but it still get stuck and sometimes runs into an infinite loop …

EDIT

Used splice instead of delete and it doesn’t get stuck anymore but I still get this error Game.winningCombinations[max] is not iterable

How to use google geocode’s long and lat outside of internal scope?

The return node is not set before geocode is done. How can I make sure the node is set to my desired values before it is returned?

function convertAddress(address) {
  var geocoder = new google.maps.Geocoder();
  var node = [0,0]

  geocoder.geocode( { 'address': address}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      var latitude = results[0].geometry.location.lat();
      var longitude = results[0].geometry.location.lng();
      node = [latitude, longitude];
    }
  });
  return node;
}

Creating a WhatsApp Activity Tracking App – Is It Possible? [closed]

I would like to start a discussion regarding the development of a WhatsApp activity tracking application. The concept is relatively straightforward: a user enters the application, provides a phone number, and the app then tracks the user’s online and offline status, along with the duration spent in the WhatsApp application, down to the day and hour. This functionality is similar to popular applications like “Last Seen.” But the question is, how can it be accomplished? Are there APIs available that can provide access to this data for programming purposes?

Is There an API for WhatsApp Activity Tracking?:
One of the first questions that arise when considering the development of such an application is whether there is an API that can provide the necessary information. Can it be used in the programming process, and if so, how? The existence of an official WhatsApp API for accessing user activity status is crucial in determining the feasibility of this project.

I am currently in the process of learning how to develop this application, specifically how to obtain information about a user’s activity status, such as whether they are online or offline, and the duration of their activity

Struggling with React hooks – AuthProvider

I’m trying to make a React App with my little knowdlege and using gpt. The thing is I want to prevent strangers from getting into the crud dashboard.

I have this in my App.js

import { AuthProvider, useAuth } from './components/authContext';

            <Route path="/dashboard" element=
            {userAuthenticated ? <CompShowProducts /> : <Navigate to="/login" />} />

Obviously all of the ‘return’ part it’s wrapped in < AuthProvider >.

This is how I handle the submit in the Login component

const handleSubmit = async (e) => {
    e.preventDefault();
    console.log('handleSubmit iniciado');
    const isAuthenticated = await login(email, password);
    console.log(isAuthenticated)
    if (isAuthenticated) {
      console.log('Redirigiendo a /dashboard');
      navigate('/dashboard');
    } else {
      setError('Autenticación fallida');
    }
  };

And this is my AuthContext

import { createContext, useContext, useState } from "react";
import axios from 'axios';

const API = process.env.REACT_APP_API_URL;

const AuthContext = createContext({
  userAuthenticated: false,
  login: async () => {
    console.warn("AuthContext#login used without provider");
    return false;
  },
  logout: () => {
    console.warn("AuthContext#logout used without provider");
  },
});

export function AuthProvider({ children }) {
  const [userAuthenticated, setUserAuthenticated] = useState(false);

  const login = async (email, password) => {
    try {
      console.log('Intentando iniciar sesión con email:', email);
      const response = await axios.post(`${API}users/login/`, { email, password });
      console.log('Valor de response.data.isAuthenticated:', response.data.isAuthenticated)
      if (response.data.isAuthenticated) {
        setUserAuthenticated(true);
        console.log('Valor de userAuthenticated:', userAuthenticated);
        return true;
      } else {
        console.log('Autenticación fallida.');
        return false;
      }
    } catch (error) {
      console.error('Error en el inicio de sesión:', error);
      return false;
    }
  };

  const logout = () => {
    setUserAuthenticated(false);
  };

  return (
    <AuthContext.Provider value={{ userAuthenticated, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  return useContext(AuthContext);
}

I found out that the userAuthenticated that App.js is getting is the one declared on AuthContext-line 7, but the login function is setting the userAuthenticated in line 18 (and so is logout function).
When adding some console.log in the code, I get that line 7’s userAuthenticated is always false, while line’s 18 userAuthenticated is the one that it’s setted as true – that makes that Login.js tries to redirect to /dashboard while App.js prevents it.

I understand that my code may not be following good practrices, I’m just starting to learn to code with React, so feel free to modify/change anything you think it’s just wrong.

I also apologize for my bad english, I’m argentinian

Thank you very much

I can’t get my data to display on my handlebars page

So I’m able to save the data I’m trying to access into my database, it logs on the webpage upon it’s event listener as well, with the correct value, half the data that I’m trying to display even shows up for every card, however, the other half of the data, while being stored, and console loggable, is not displaying on my webpage. I’m not even sure where to look or what to do at this point. If anyone has any recommendations, I’d greatly appreciate them!

{{#if RatingMovies}}
  {{#each RatingMovies}}
      <div class="column is-one-third">
  <div class="card">
    <div class="card-image">
      <figure class="image">
        <img src="{{poster}}" alt="{{title}} Poster">
      </figure>
    </div>
    <div class="card-content">
      <div class="media">
        <div class="media-content">
          <p class="title is-4">{{title}}</p>
          <p class="subtitle is-6">Type: {{type}}</p>
          <p class="subtitle is-6">Release Date: {{release_date}}</p>
          <p class="subtitle is-6">Rating: {{rating}}</p>
          <p class="subtitle is-6">IMDB Id: {{imdb_id}}</p>
        </div>
      </div>
    </div>
  </div>
</div>
  {{/each}}
{{else}}
  <p>No rated movies yet.</p>
{{/if}}

my data for title, poster, rating, and imdb_id all display, however I receive nothing on my webpage for release_date and type

Mongo/Mongoose will not pass a string

Attempting to connect to MongoDB via a follow-along, and I keep getting this error:

The uri parameter to openUri() must be a string, got “undefined”. Make sure the first parameter to mongoose.connect() or mongoose.createConnection() is a string.

Here is the code I’m working with:
.env file (I changed the username and password. The name is cluster0)

MONGO_URI="mongodb+srv://username:[email protected]/?retryWrites=true&w=majority"

Server.js

dotenv.config();

mongoose
  .connect(process.env.MONGODB_URI)

  .then(() => {
    console.log("connected to db");
  })
  .catch((err) => {
    console.log(err.message);
  });

Any help is appreciated, let me know what other info I can provide. Thank you.

How to identify the field I’m sending via submit in Svelte?

I’m using the component InPlaceEdit and I’m trying to change a text in a table.

When I make a change in the text, this makes an API call and update the value.

However, I don’t know how to identify what field I’m requesting to modify therefore I have it hardcoded at the moment.

So let’s say I have categories, expenses and savings and each of them have id, name, price, etc..

so to access the values it would be categories.id or categories.name

I would like the code to recognise what exactly I’m changing.

This is my

onMount(async function () {
        const endpoint = 'http://blablabla/'
        const response = await fetch(endpoint)
        const data = await response.json()
        ExpenseStore.set(data)
    })

    function submit(field) {
        
        return ({detail: newValue}) => {
            
                const endpoint = `http://blablabla/${field.id}`
                let data = new FormData()

                field.toArray().forEach((concept, index) => {
                    const num2 = data[index];
                    console.log(concept, num2);
                })

                /*
                SOLUTION
                FOR EACH data and FIELD
                IF DATA[0] == FIELD[0] (en valor) 
                    then data.append(field[0].meta, field[0]])
                ELSE
                    data.append(field[0].meta, newValue)
                */

                data.append('name', newValue)
                data.append('expensecategory', field.expensecategory)
                data.append('monthly_amount', field.monthly_amount)
                data.append('payment_frequency', field.payment_frequency)
                data.append('year', field.year)
                data.append('yearly_amount', field.yearly_amount)

                fetch(endpoint , {method: 'PUT', body: data}).then(response => response.json()).then(data => {
                    console.log(data)
                })
            // IRL: POST value to server here
            console.log(`updated ${field.id}, new value is: "${newValue}"`)
        }
    }

This is the logic I think I should follow but I cannot make it work

SOLUTION
FOR EACH data and FIELD
IF DATA[0] == FIELD[0] (en valor) 
    then data.append(field[0].meta, field[0]])
ELSE
    data.append(field[0].meta, newValue)
            

And this is the body:

{#each $ExpenseStore as expense, index (expense.id)}
<html code>                         
    <InPlaceEdit bind:value={expense.name} on:submit={submit(expense)}/>
<html code>
{/each}

I’m thinking, how can I send the metadata of the object via submit or bind?
So for example, if I was able to send ‘name’ from expense.name, I could modify just that field. So what I’m missing here?

I cannot retrieve the value of price of the selected product name in mysql database, it only display a NaN

I created a javascript that would add the selected product to the table from a dropdown in my html that would also retrieve the price of the selected product but it only displays a NaN instead of the actual price that corresponds to the product

sales.js

var row = 1;

function addProduct() {
    var selectedProduct = document.getElementById("product_list");
    var productName = selectedProduct.options[selectedProduct.selectedIndex].value;
    var qty = document.getElementById("product_qty").value;

    if (!productName) {
        BootstrapDialog.alert({
            type: BootstrapDialog.TYPE_DANGER,
            message: 'Invalid product.',
        });
    } else if (!qty || qty < 1) {
        BootstrapDialog.alert({
            type: BootstrapDialog.TYPE_DANGER,
            message: 'Invalid product quantity.',
        });
    } else {
        fetchProductPrice(productName, function (price) {
            var display = document.getElementById("display");
            var newRow = display.insertRow();

            var cell1 = newRow.insertCell(0);
            var cell2 = newRow.insertCell(1);
            var cell3 = newRow.insertCell(2);
            var cell4 = newRow.insertCell(3);
            var cell5 = newRow.insertCell(4);

            cell1.innerHTML = productName;
            cell2.innerHTML = price.toFixed(2);
            cell3.innerHTML = qty;
            cell4.innerHTML = (price * qty).toFixed(2);
            cell5.innerHTML = '<button type="button" class="delete" onclick="removeItem(this)">Delete</button>';

            row++;

            selectedProduct.selectedIndex = 0;
            document.getElementById('product_qty').value = '';

            updateTotalPrice();
        });
    }
}

function fetchProductPrice(productName, callback) {
    $.ajax({
        url: 'database/get_product_price.php',
        method: 'POST',
        data: { product_name: productName },
        success: function (response) {
            var price = parseFloat(response);
            callback(price);
        },
        error: function () {
            alert('Error fetching product price.');
        },
    });
}

function removeItem(button) {
    var row = button.parentNode.parentNode;
    row.parentNode.removeChild(row);
}

//get_product_price.php

<?php
    include('database/connection.php');

    try {
        // Establish database connection (code should be present in 'connection.php')

        if (isset($_POST['product_name'])) {
            $productName = $_POST['product_name'];
            
            $stmt = $conn->prepare("SELECT price FROM tbl_products WHERE product_name = ?");
            $stmt->execute([$productName]);

            $row = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($row) {
                echo $row['price'];
            } else {
                echo '0'; // You can return some default value if the product is not found
            }
        } else {
            echo '0'; // Handle invalid requests
        }
    } catch (PDOException $e) {
        echo 'Database error: ' . $e->getMessage();
    }
?>

enter image description here

I was expecting to retrieve the float value of price based on the selected product instead of getting a “NaN”

Using Axios to play sound from an URL using javascript

I’m trying to use axios to play sound from a url

soundUrl = `https://cdn.freesound.org/previews/213/213889_2287873-lq.ogg`
const response = await axios.get(soundUrl, {
        responseType: 'stream',
      });

      if (response.status === 200) {
        // Create a Speaker instance to play the sound
        const speaker = new Speaker();
        // Pipe the response data stream directly to the speaker
        response.data.pipe(speaker);
}

However, all this does is play a static noise.

I also tried to download the file directly from this download link: https://freesound.org/people/Counter-gamer/sounds/213889/download/213889__counter-gamer__the-cats-meow.wav

using axios, then playing the downloaded file, but the audio is not successfully downloaded.

I also tried using this:

player.play(soundUrl, (err) => {
        if (err) {
          console.error('Error playing audio:', err);
        } else {
          console.log('Audio played successfully');
        }
      });

How to set @Url.Content for an image in AngularJs MVC Application

I am trying to upload an image and display it in my application. I am working in AngularJS, MVC and Web APi. My Image uploads successfully to a folder.

Issue is: After uploading I send back relative path as Http response and set it to my controller $scope property which in turn I want to bind with img src. I am not sure if this is proper way to do it or not. Please guide is this wrong or what I am doing wrong.

My view is:

 <div class="profilePic">
       <img src="@Url.Content(UserDetails.PrflPic)" alt="Sample Image" />
 </div>
 <input type="file" valid-file upload="uploadFile(file)" ng-model="file">

Here “UserDetails.PrflPic” is my $scope property that I want to use some how. But, I cannot do this because Url.Content takes string only. I tried this @Url.Content({{UserDetails.PrflPic}}) which also is not fine.

My Controller Method is:

$scope.uploadFile = function (file) {
        
        var PromiseData = UserService.uploadProfilePicture(file);
        PromiseData.then(function (Response) {
            alertify.alert('Image uploaded sucessfully');
            $scope.UserDetails.PrflPic = Response.data;
            $scope.$apply();
           
        }, function (Error) {$scope.$apply();
            alertify.alert('Some issue occurred while saving picture');
        });
    }

File Upload Api as:

 public IHttpActionResult Post()
        {
            var httpRequest = HttpContext.Current.Request;

            // Check if files are available
            if (httpRequest.Files.Count > 0)
            {
                var postedFile = httpRequest.Files[0];

                var path = System.Web.Hosting.HostingEnvironment.MapPath("~/UserProfilePic/");
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                // Fetch the File Name.
                string fileName = Path.GetFileName(postedFile.FileName);

                // Save the File.
                postedFile.SaveAs(path + fileName);

                var ImgLoc = "~/UserProfilePic/" + fileName;
                return Content(HttpStatusCode.OK, ImgLoc);
            }
            else
            {
                return BadRequest("No files to upload.");
            }
        }

Why does Typescript running getters and setters have a massive performance degradation of 315% in a high performance situation of an animation loop

Here are the numbers. I had to figure out and then do a reversal of it. Am I missing something here. Why is it so dramatic?

I refactored some code and decided to use get and set instead of just the normal property class initiation. Using Angular and typescript for reference. I noticed that the animation was immediately slow. I couldn’t figure out what was going on. I reverted the gets and sets back to a normal prop and there it was. I did the math and it is a 315% performance degradation. I was really surprised by that.

Metric With Getters/Setters Without Getters/Setters Degradation
Start Time 19:21:49.720 19:28:30.978 N/A
End Time 19:22:03.742 19:28:34.356 N/A
Execution Duration (seconds) 14.022 3.378 315%

Cannot fetch JSON data?

I keep getting the error “SyntaxError: Unexpected end of input” when I try to fetch. What’s wrong?
(i type in my browser: file:///C:/websites/test/a.html.)

a.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fetch API Demo</title>

</head>
<body>
    <div class="container"></div>
    <script src="js/app.js"></script>
</body>
</html>`

app.js:

async function getUsers() {
    let url = 'https://goldduo.com/users.json';

    try {
        let res = await fetch(url, {mode: 'no-cors'});
        const x=await res.json();
        console.log(x);
    } catch (error) {
        console.log(error);
    } 
}

getUsers();

I tried modifying and simplifying the JSON data. I also tried printing out res.text(), but it’s blank.

Gannt chart – limiting the size of the brush and auto selecting a fraction of the timeline at the start

I’ve built a d3.js gannt chart – but I am struggling to get the brush to be a fixed width/smaller scope – on load – showing only a small portion of the timeline, instead of the entire timeline.

I want the chart to load in like this – rather then global/full width.

enter image description here

https://codesandbox.io/s/objective-villani-qngrlj

I’ve tried manipulating the x1.range() – or adding extent – or trying to modify the brushed functions – but I’ve either found very old examples or it breaks the codebase I have.

https://observablehq.com/@d3/click-to-recenter-brush?collection=@d3/d3-brush

codebase currently

import React from 'react'
import * as d3 from 'd3'
//import './GanttChart1.scss'

class GanttChart extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
    this.state = {
      data: this.props.data ? this.props.data : [],
      theme: this.props.theme
        ? this.props.theme
        : ['#bde0fe', '#2698f9', '#71bcfd', '#f1f8fe'],
    }
  }

  componentWillReceiveProps(nextProps) {
    // You don't have to do this check first, but it can help prevent an unneeded render
    if (nextProps.data !== this.state.data) {
      //console.log("PROPS HAVE CHANGED FOR CHART");
      this.setState({data: nextProps.data})
      this.buildChart()
    }
  }

  componentDidMount() {
    this.buildChart()
  }

  buildChart() {
    var $this = this.myRef.current

    d3.select($this).selectAll('svg').remove()

    //var data = this.props.data;

    //data for chart
    var data = [
      {
        label: 'person a',
        avatar:
          'https://cdn.britannica.com/61/137461-050-BB6C5D80/Brad-Pitt-2008.jpg',
        times: [
          {
            text: 'Test 1',
            starting_time: 1355752800000,
            ending_time: 1355759900000,
          },
          {
            text: 'Test 2',
            starting_time: 1355767900000,
            ending_time: 1355774400000,
          },
        ],
      },
      {
        label: 'person b',
        avatar:
          'https://media.onvoitout.fr/2021/10/Compress_20211028_135754_4577.jpg',
        times: [
          {
            text: 'Test 3',
            starting_time: 1355767900000,
            ending_time: 1355774400000,
          },
        ],
      },
      {
        label: 'person c',
        avatar:
          'https://ichef.bbci.co.uk/news/624/mcs/media/images/77876000/jpg/_77876037_cara2.jpg',
        times: [
          {
            text: 'Test 4',
            starting_time: 1355761910000,
            ending_time: 1355763910000,
          },
        ],
      },
      {
        label: 'person d',
        avatar:
          'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQLThUPE00PBf-es9Y3teevd5qws4O1-5vQSZEYvF6I4IyZVi9tfi4Wt_sBKgbXbEhvycs&usqp=CAU',
        times: [
          {
            text: 'Test 5',
            starting_time: 1355861000000,
            ending_time: 1355865900000,
          },
        ],
      },
      {
        label: 'person e',
        avatar:
          'https://www.wellandgood.com/wp-content/uploads/2022/09/celebrity-beauty-brands-425x285.jpg',
        times: [
          {
            text: 'Test 11',
            starting_time: 1355861900000,
            ending_time: 1355864520000,
          },
          {
            text: 'Test 12',
            starting_time: 1355777900000,
            ending_time: 1355784400000,
          },
        ],
      },
      {
        label: 'person e',
        avatar:
          'https://www.shutterstock.com/image-photo/cannes-france-may-21-leonardo-260nw-1433831474.jpg',
        times: [
          {
            text: 'Test 11',
            starting_time: 1355752800000,
            ending_time: 1355759900000,
          },
          {
            text: 'Test 12',
            starting_time: 1355967900000,
            ending_time: 1355994400000,
          },
        ],
      },
    ]

    var tooltip = d3
      .select('body')
      .append('div')
      .attr('class', 'tooltip')
      .style('opacity', 0)
      .style('display', 'none')

    //setting data formate for chart
    var lanes = []
    var times = []
    var avatars = []

    //var data = this.state.data;

    data.forEach((value, index) => {
      lanes.push(value.label)
      avatars.push(value.avatar)

      value.times.forEach((v, i) => {
        v['lane'] = index
      })
      times.push(value.times)
    })

    var laneLength = lanes.length
    var items = [].concat.apply([], times)

    items.forEach((v, i) => {
      v['id'] = i
    })

    var timeBegin = d3.min(items, function (d) {
      return d['starting_time']
    })

    var timeEnd = d3.max(items, function (d) {
      return d['ending_time']
    })

    var width = parseInt(this.props.width, 10),
      height = parseInt(this.props.height, 10)

    var color = d3.scaleOrdinal().range(this.state.theme)

    var parseTime = d3.timeParse('%Y%m%d')

    var m = [20, 85, 10, 190], //top right bottom left
      w = width - m[1] - m[3],
      h = height - m[0] - m[2],
      miniHeight = laneLength * 12 + 50,
      mainHeight = h - miniHeight - 50

    //scales
    var x = d3.scaleTime().range([0, w]).domain([timeBegin, timeEnd])
    var x1 = d3.scaleLinear().range([0, w])
    var y1 = d3.scaleLinear().range([0, mainHeight]).domain([0, laneLength])
    var y2 = d3.scaleLinear().range([0, miniHeight]).domain([0, laneLength])

    var scaleFactor = (1 / (timeEnd - timeBegin)) * w

    var chart = d3
      .select($this)
      .append('svg')
      .attr('width', w + m[1] + m[3])
      .attr('height', h + m[0] + m[2])
      .attr('class', 'chart')

    chart
      .append('defs')
      .append('clipPath')
      .attr('id', 'clip')
      .append('rect')
      .attr('width', w)
      .attr('height', mainHeight)

    var main = chart
      .append('g')
      .attr('transform', 'translate(' + m[3] + ',' + m[0] + ')')
      .attr('width', w)
      .attr('height', mainHeight)
      .attr('class', 'main')

    var mini = chart
      .append('g')
      .attr(
        'transform',
        'translate(' + m[3] + ',' + (mainHeight + m[0] + 13) + ')',
      )
      .attr('width', w)
      .attr('height', miniHeight)
      .attr('class', 'mini')

    //background colors
    function colores_background(n) {
      var colores_g = ['#f8dd2f', '#e9168a', '#448875', '#2b2d39', '#c3bd75']
      return colores_g[n % colores_g.length]
    }

    //foreground colors
    function colores_foreground(n) {
      var colores_g = ['#553814', '#311854', '#f7b363', '#c12f39', '#89191d']
      return colores_g[n % colores_g.length]
    }

    //main lanes and texts
    main
      .append('g')
      .selectAll('.laneLines')
      .data(items)
      .enter()
      .append('line')
      .attr('x1', 0)
      .attr('y1', function (d) {
        return y1(d.lane)
      })
      .attr('x2', w)
      .attr('y2', function (d) {
        return y1(d.lane)
      })
      .attr('stroke', 'lightgray')

    var defs = main.append('svg:defs')

    main
      .append('g')
      .selectAll('.laneText')
      .data(lanes)
      .enter()
      .append('text')
      .text(function (d) {
        return d
      })
      .attr('x', -m[1] + 10)
      .attr('y', function (d, i) {
        return y1(i + 0.5)
      })
      .attr('dy', '.5ex')
      .attr('text-anchor', 'end')
      .attr('class', 'laneText')

    //mini lanes and texts
    mini
      .append('g')
      .selectAll('.laneLines')
      .data(items)
      .enter()
      .append('line')
      .attr('x1', 0)
      .attr('y1', function (d) {
        return y2(d.lane)
      })
      .attr('x2', w)
      .attr('y2', function (d) {
        return y2(d.lane)
      })
      .attr('stroke', 'lightgray')

    mini
      .append('g')
      .selectAll('.laneText')
      .data(lanes)
      .enter()
      .append('text')
      .text(function (d) {
        return d
      })
      .attr('x', -m[1] + 40)
      .attr('y', function (d, i) {
        return y2(i + 0.5)
      })
      .attr('dy', '.5ex')
      .attr('text-anchor', 'end')
      .attr('class', 'laneText')

    var itemRects = main.append('g').attr('clip-path', 'url(#clip)')

    //mini item rects
    mini
      .append('g')
      .selectAll('miniItems')
      .data(items)
      .enter()
      .append('rect')
      .attr('class', function (d) {
        return 'miniItem'
      })
      .attr('x', function (d) {
        return x(d.starting_time)
      })
      .attr('y', function (d) {
        return y2(d.lane + 0.5) - 5
      })
      .attr('fill', function (d, i) {
        return colores_background(d.lane)
      })
      .attr('width', function (d) {
        return (d.ending_time - d.starting_time) * scaleFactor
      })
      .attr('height', 10)

    //this is for avatars user images
    avatars.forEach((value, index) => {
      defs
        .append('svg:pattern')
        .attr('id', '--' + index)
        .attr('width', 1)
        .attr('height', 1)
        .append('svg:image')
        .attr('image-rendering', 'optimizeQuality')
        .attr('preserveAspectRatio', 'xMidYMid meet')
        .attr('xlink:href', value)
        .attr('x', 0)
        .attr('y', 0)
        .attr('width', 50)
        .attr('height', 50)

      defs
        .append('svg:pattern')
        .attr('id', '--m' + index)
        .attr('width', 1)
        .attr('height', 1)
        .append('svg:image')
        .attr('image-rendering', 'optimizeQuality')
        .attr('preserveAspectRatio', 'xMidYMid meet')
        .attr('xlink:href', value)
        .attr('x', 0)
        .attr('y', 0)
        .attr('width', 20)
        .attr('height', 20)

      //draw the x axis on time
      main
        .append('g')
        .attr('transform', function (d, i) {
          return 'translate(' + (-m[1] + 5) + ',' + (y1(index + 0.5) - 50) + ')'
        })
        .append('circle')
        .attr('class', 'user-avatar')
        //.style("stroke", "gray")
        .style('fill', 'url(#--' + index + ')')
        .attr('r', 25)
        .attr('cx', 40)
        .attr('cy', 50)

      mini
        .append('g')
        .attr('transform', function (d, i) {
          return (
            'translate(' + (-m[1] + 40) + ',' + (y2(index + 0.5) - 20) + ')'
          )
        })
        .append('circle')
        .attr('class', 'user-avatar')
        //.style("stroke", "gray")
        .style('fill', 'url(#--m' + index + ')')
        .attr('r', 10)
        .attr('cx', 20)
        .attr('cy', 20)
    })

    //draw x axis

    function toDays(d) {
      d = d || 0
      return d / 24 / 60 / 60 / 1000
    }
    function toUTC(d) {
      if (!d || !d.getFullYear) return 0
      return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())
    }

    //find best range
    var days = daysBetween(new Date(timeBegin), new Date(timeEnd))

    function daysBetween(d1, d2) {
      return toDays(toUTC(d2) - toUTC(d1))
    }

    var tFormat1 = '%Y-%m'
    var tTick1 = 'timeMonths'

    if (days < 40) {
      tFormat1 = '%Y-%m-%d'
      tTick1 = 'timeWeek'
    }

    if (days <= 7) {
      tFormat1 = '%b %Y'
      tTick1 = 'timeDay'
    }

    if (days <= 1) {
      tFormat1 = '%H%M'
      tTick1 = 'timeHour'
    }

    // draw the x axis on date and years
    var xMonthAxis = d3
      .axisTop(x)
      .tickArguments(d3[tTick1], 1)
      .tickFormat(d3.timeFormat(tFormat1))
      .tickSize(15)

    //for years on top
    mini
      .append('g')
      .attr('transform', 'translate(0,0.5)')
      .attr('class', 'axis month')
      .call(xMonthAxis)
      .selectAll('text')
      .attr('dx', 25)
      .attr('dy', 15)

    var gX = chart
      .append('g')
      .attr('class', 'axis axis-x')
      .attr('transform', 'translate(' + m[3] + ',' + 450 + ')')
      .call(d3.axisBottom(x))
    //draw x axis

    //call brush function
    var brush = d3
      .brushX()
      .extent([
        [0, 0],
        [w, miniHeight],
      ])
      .on('brush', brushed)

    mini
      .append('g')
      .attr('class', 'x brush')
      .call(brush)
      .call(brush.move, x1.range())
      .selectAll('rect')
      .attr('y', 1)
      .attr('height', miniHeight - 1)

    //create brush function redraw scatterplot with selection

    function brushed(event) {
      var selection = event.selection
      var timeSelection = selection.map(x.invert, x)

      var rects
      var labels
      var minExtent = timeSelection[0]
      var maxExtent = timeSelection[1]

      var visItems = items.filter(function (d) {
        return d.starting_time < maxExtent && d.ending_time > minExtent
      })

      x1.domain([minExtent, maxExtent])

      //update main item rects
      rects = itemRects
        .selectAll('rect')
        .data(visItems, function (d) {
          return d.id
        })
        .attr('x', function (d) {
          return x1(d.starting_time)
        })
        .attr('width', function (d) {
          return x1(d.ending_time) - x1(d.starting_time)
        })

      rects
        .enter()
        .append('rect')
        .attr('class', function (d) {
          return 'miniItem'
        })
        .attr('x', function (d) {
          return x1(d.starting_time)
        })
        .attr('y', function (d) {
          return y1(d.lane) + 5
        })
        .attr('fill', function (d, i) {
          return colores_background(d.lane)
        })
        .attr('width', function (d) {
          return x1(d.ending_time) - x1(d.starting_time)
        })
        .attr('height', function (d) {
          return 0.8 * y1(1)
        })
        .on('mouseover', function (d, i) {
          tooltip
            .transition()
            .duration(200)
            .style('opacity', 0.9)
            .style('display', 'block')

          tooltip
            .html(`${d.target.__data__.text}`)
            .style('left', d.pageX + 5 + 'px')
            .style('top', d.pageY + 5 + 'px')
        })
        .on('mouseout', function (d) {
          tooltip
            .transition()
            .duration(500)
            .style('opacity', 0)
            .style('display', 'none')
        })

      rects.exit().remove()

      /*
            //update the item labels
            labels = itemRects.selectAll("text")
              .data(visItems, function(d) {
                return d.id;
              })
              .attr("x", function(d) {
                return x1(Math.max(d.starting_time, minExtent) + 2);
              });

            labels.enter().append("text")
              .text(function(d) {
                return d.text;
              })
              .attr("x", function(d) {
                return x1(Math.max(d.starting_time, minExtent));
              })
              .attr("y", function(d) {
                return y1(d.lane + .5);
              })
              .attr("fill", function(d, i) {
                return colores_foreground(d.lane);
              })
              .attr("text-anchor", "start");

            labels.exit().remove();
            */
    }
  }

  render() {
    return <div ref={this.myRef} className="GanttChart" />
  }
}
export default GanttChart