Create a workflow statistics page from Jira
This commit is contained in:
		
							parent
							
								
									010fe6e650
								
							
						
					
					
						commit
						9b630fe1e1
					
				| 
						 | 
				
			
			@ -76,7 +76,7 @@ class JiraService
 | 
			
		|||
                "assignee = '%s' AND status IN ('backlog', 'todo', 'in progress')",
 | 
			
		||||
                $accountId
 | 
			
		||||
            ),
 | 
			
		||||
            'maxResults' => 10,
 | 
			
		||||
            'maxResults' => 50,
 | 
			
		||||
            'startAt' => $startAt
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ class JiraService
 | 
			
		|||
        $body = [
 | 
			
		||||
            'jql' => "worklogAuthor = '{$accountId}'AND worklogDate >= '{$startDate}' AND worklogDate <= '{$endDate}'",
 | 
			
		||||
            'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'project'],
 | 
			
		||||
            'maxResults' => 50
 | 
			
		||||
            'maxResults' => 100
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = $this->client->post('/rest/api/3/search', [
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +134,7 @@ class JiraService
 | 
			
		|||
                ]
 | 
			
		||||
            ])->then(function ($checkApiResponse) use ($issueId, $index) {
 | 
			
		||||
                $checkApi = json_decode($checkApiResponse->getBody()->getContents(), true);
 | 
			
		||||
                $maxResults = 50;
 | 
			
		||||
                $maxResults = 100;
 | 
			
		||||
                $totalWorklogs = $checkApi['total'];
 | 
			
		||||
                return $this->client->getAsync("/rest/api/3/issue/{$issueId}/worklog", [
 | 
			
		||||
                    'query' => [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,8 +116,13 @@ const Tracking = () => {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(()=>{
 | 
			
		||||
    setInterval(()=>{
 | 
			
		||||
    if(listTracking.data.length === 0){
 | 
			
		||||
      getAllTracking()
 | 
			
		||||
    }
 | 
			
		||||
    setInterval(()=>{
 | 
			
		||||
      if(window.location.pathname.includes('tracking')){
 | 
			
		||||
        getAllTracking()
 | 
			
		||||
      }
 | 
			
		||||
    }, 7000)
 | 
			
		||||
  }, [])
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,7 +117,7 @@ const Worklogs = () => {
 | 
			
		|||
    startDate:
 | 
			
		||||
      localStorage.getItem('data') !== null
 | 
			
		||||
        ? JSON.parse(localStorage.getItem('data')!).date.startDate
 | 
			
		||||
        : moment(Date.now()).format('YYYY-MM-DD'),
 | 
			
		||||
        : moment(Date.now()-604800000).format('YYYY-MM-DD'),
 | 
			
		||||
    endDate:
 | 
			
		||||
      localStorage.getItem('data') !== null
 | 
			
		||||
        ? JSON.parse(localStorage.getItem('data')!).date.endDate
 | 
			
		||||
| 
						 | 
				
			
			@ -172,65 +172,88 @@ const Worklogs = () => {
 | 
			
		|||
    </Box>
 | 
			
		||||
  ) : (
 | 
			
		||||
    <div style={{ display: 'flex', flexFlow: 'column' }}>
 | 
			
		||||
      <div className={classes.title}>
 | 
			
		||||
        <h3>
 | 
			
		||||
          <Text>Admin/</Text>Worklogs
 | 
			
		||||
          {!updating ? (
 | 
			
		||||
            <Text fs={'italic'} fz={'xs'} c={'gray'}>
 | 
			
		||||
              Updating data in the background ...
 | 
			
		||||
            </Text>
 | 
			
		||||
          ) : (
 | 
			
		||||
            ''
 | 
			
		||||
          )}
 | 
			
		||||
        </h3>
 | 
			
		||||
      </div>
 | 
			
		||||
      <Box
 | 
			
		||||
        display={'flex'}
 | 
			
		||||
        w={'30%'}
 | 
			
		||||
        style={{
 | 
			
		||||
          float: 'right',
 | 
			
		||||
          // margin: '10px',
 | 
			
		||||
          alignItems: 'end',
 | 
			
		||||
          justifyContent: 'space-between',
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <DateInput
 | 
			
		||||
          size="xs"
 | 
			
		||||
          label="From date:"
 | 
			
		||||
          value={new Date(date.startDate)}
 | 
			
		||||
          w={'40%'}
 | 
			
		||||
          clearable
 | 
			
		||||
          onChange={(e) => {
 | 
			
		||||
            setDate({ ...date, startDate: moment(e).format('YYYY-MM-DD') })
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
        <DateInput
 | 
			
		||||
          size="xs"
 | 
			
		||||
          label="To date:"
 | 
			
		||||
          value={new Date(date.endDate)}
 | 
			
		||||
          clearable
 | 
			
		||||
          w={'40%'}
 | 
			
		||||
          onChange={(e) => {
 | 
			
		||||
            setDate({ ...date, endDate: moment(e).format('YYYY-MM-DD') })
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
        <Button
 | 
			
		||||
          size="xs"
 | 
			
		||||
          onClick={() => {
 | 
			
		||||
            getAllWorklogs()
 | 
			
		||||
    <div className={classes.title}>
 | 
			
		||||
      <h3>
 | 
			
		||||
        <Text>Admin/</Text>Worklogs
 | 
			
		||||
        {!updating ? (
 | 
			
		||||
          <Text fs={'italic'} fz={'xs'} c={'gray'}>
 | 
			
		||||
            Updating data in the background ...
 | 
			
		||||
          </Text>
 | 
			
		||||
        ) : (
 | 
			
		||||
          ''
 | 
			
		||||
        )}
 | 
			
		||||
      </h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    <Box
 | 
			
		||||
      display={'flex'}
 | 
			
		||||
      style={{
 | 
			
		||||
        flexFlow: 'column',
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <Text fz={12} fs={'italic'} c={'red'} fw={600} mt={'md'}>
 | 
			
		||||
        {`* The current data is from ${JSON.parse(localStorage.getItem('data')!).date.startDate} to ${JSON.parse(localStorage.getItem('data')!).date.endDate}`}
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Text fz={12} fs={'italic'} c={'red'} fw={600}>
 | 
			
		||||
        {`* If you need data outside this time period, please select a date and click "Search" to update the latest data.`}
 | 
			
		||||
      </Text>
 | 
			
		||||
      <Box w={'100%'} display={'flex'} style={{ flexFlow: 'column' }}>
 | 
			
		||||
        <Box
 | 
			
		||||
          w={'100%'}
 | 
			
		||||
          display={'flex'}
 | 
			
		||||
          style={{
 | 
			
		||||
            alignItems: 'end',
 | 
			
		||||
            // justifyContent: 'space-between',
 | 
			
		||||
            flexWrap: 'wrap',
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          Search
 | 
			
		||||
        </Button>
 | 
			
		||||
          <DateInput
 | 
			
		||||
            size="xs"
 | 
			
		||||
            label="From date:"
 | 
			
		||||
            value={new Date(date.startDate)}
 | 
			
		||||
            w={'20%'}
 | 
			
		||||
            clearable
 | 
			
		||||
            onChange={(e) => {
 | 
			
		||||
              setDate({ ...date, startDate: moment(e).format('YYYY-MM-DD') });
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
          <DateInput
 | 
			
		||||
            size="xs"
 | 
			
		||||
            label="To date:"
 | 
			
		||||
            value={new Date(date.endDate)}
 | 
			
		||||
            clearable
 | 
			
		||||
            m={"0 10px"}
 | 
			
		||||
            w={'20%'}
 | 
			
		||||
            onChange={(e) => {
 | 
			
		||||
              setDate({ ...date, endDate: moment(e).format('YYYY-MM-DD') });
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
          <Button
 | 
			
		||||
            size="xs"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              getAllWorklogs();
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Search
 | 
			
		||||
          </Button>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </Box>
 | 
			
		||||
      {/* Box main content */}
 | 
			
		||||
      <Box display={'flex'} mt={'lg'}>
 | 
			
		||||
        <Box w={'10%'} >
 | 
			
		||||
          <Text fw={700} fz={14}>
 | 
			
		||||
            Members
 | 
			
		||||
          </Text>
 | 
			
		||||
          <Box style={{border:"solid 1px gray", padding:"10px", marginRight:"10px", borderRadius:"5px", boxShadow: '1px 1px 5px 1px gray',}}>
 | 
			
		||||
            {worklogs.map((w) => (
 | 
			
		||||
    </Box>
 | 
			
		||||
    {/* Box main content */}
 | 
			
		||||
    <Box display={'flex'} mt={'lg'} style={{ flexWrap: 'wrap' }}>
 | 
			
		||||
      <Box w={{ base: '100%', md: '15%' }} mb={'lg'}>
 | 
			
		||||
        <Text fw={700} fz={14}>
 | 
			
		||||
          Members
 | 
			
		||||
        </Text>
 | 
			
		||||
        <Box
 | 
			
		||||
          style={{
 | 
			
		||||
            border: 'solid 1px gray',
 | 
			
		||||
            padding: '10px 20px',
 | 
			
		||||
            marginRight: '10px',
 | 
			
		||||
            borderRadius: '5px',
 | 
			
		||||
            boxShadow: '1px 1px 5px 1px gray',
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          {worklogs.map((w) => (
 | 
			
		||||
            <Box
 | 
			
		||||
              key={w.username}
 | 
			
		||||
              style={{
 | 
			
		||||
| 
						 | 
				
			
			@ -251,309 +274,259 @@ const Worklogs = () => {
 | 
			
		|||
              </a>
 | 
			
		||||
            </Box>
 | 
			
		||||
          ))}
 | 
			
		||||
          </Box>
 | 
			
		||||
          
 | 
			
		||||
        </Box>
 | 
			
		||||
        <Box
 | 
			
		||||
          w={'90%'}
 | 
			
		||||
          h={'85vh'}
 | 
			
		||||
          display={'flex'}
 | 
			
		||||
          style={{ overflowX: 'auto', flexFlow: 'column' }}
 | 
			
		||||
        >
 | 
			
		||||
          {worklogs?.map((user, index) => (
 | 
			
		||||
            // Box user
 | 
			
		||||
            <Box
 | 
			
		||||
              id={user.username}
 | 
			
		||||
              key={index}
 | 
			
		||||
              p={'sm'}
 | 
			
		||||
              style={{
 | 
			
		||||
                border: 'solid 1px gray',
 | 
			
		||||
                borderRadius: '5px',
 | 
			
		||||
                borderColor: '#afafaf',
 | 
			
		||||
                marginBottom: '10px',
 | 
			
		||||
                backgroundColor:
 | 
			
		||||
                  index % 2 === 0 ? 'rgb(201 201 201 / 28%)' : 'white',
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              <Text ta={'left'} mb={'xs'} fw={800} display={'flex'}>
 | 
			
		||||
                <Avatar
 | 
			
		||||
                  src={user.user.avatarUrls['48x48']}
 | 
			
		||||
                  size={'sm'}
 | 
			
		||||
                  m={'0 5px'}
 | 
			
		||||
                />
 | 
			
		||||
                {user.username}(
 | 
			
		||||
                {user?.information.issues.reduce(
 | 
			
		||||
                  (total: number, issue: Issue) => {
 | 
			
		||||
                    var totalSpent = issue.fields.worklog.worklogs?.reduce(
 | 
			
		||||
                      (accumulator: number, currentValue: WorkLog) => {
 | 
			
		||||
                        if (
 | 
			
		||||
                          parseInt(moment(date.startDate).format('YYYYMMDD')) <=
 | 
			
		||||
                            parseInt(
 | 
			
		||||
                              moment(currentValue.started).format('YYYYMMDD'),
 | 
			
		||||
                            ) &&
 | 
			
		||||
                          parseInt(
 | 
			
		||||
                            moment(currentValue.started).format('YYYYMMDD'),
 | 
			
		||||
                          ) <=
 | 
			
		||||
                            parseInt(moment(date.endDate).format('YYYYMMDD')) &&
 | 
			
		||||
                          currentValue.updateAuthor.displayName ===
 | 
			
		||||
                            user.username
 | 
			
		||||
                        ) {
 | 
			
		||||
                          return accumulator + currentValue.timeSpentSeconds
 | 
			
		||||
                        }
 | 
			
		||||
                        return accumulator
 | 
			
		||||
                      },
 | 
			
		||||
                      0,
 | 
			
		||||
                    )
 | 
			
		||||
                    return total + totalSpent
 | 
			
		||||
      </Box>
 | 
			
		||||
      <Box
 | 
			
		||||
        w={{ base: '100%', md: '85%' }}
 | 
			
		||||
        h={'85vh'}
 | 
			
		||||
        display={'flex'}
 | 
			
		||||
        style={{ overflowX: 'auto', flexFlow: 'column' }}
 | 
			
		||||
      >
 | 
			
		||||
        {worklogs?.map((user, index) => (
 | 
			
		||||
          // Box user
 | 
			
		||||
          <Box
 | 
			
		||||
            id={user.username}
 | 
			
		||||
            key={index}
 | 
			
		||||
            p={'sm'}
 | 
			
		||||
            style={{
 | 
			
		||||
              border: 'solid 1px gray',
 | 
			
		||||
              borderRadius: '5px',
 | 
			
		||||
              borderColor: '#afafaf',
 | 
			
		||||
              marginBottom: '10px',
 | 
			
		||||
              backgroundColor: index % 2 === 0 ? 'rgb(201 201 201 / 28%)' : 'white',
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <Text ta={'left'} mb={'xs'} fw={800} display={'flex'}>
 | 
			
		||||
              <Avatar src={user.user.avatarUrls['48x48']} size={'sm'} m={'0 5px'} />
 | 
			
		||||
              {user.username}(
 | 
			
		||||
              {user?.information.issues.reduce((total, issue) => {
 | 
			
		||||
                const totalSpent = issue.fields.worklog.worklogs?.reduce(
 | 
			
		||||
                  (accumulator, currentValue) => {
 | 
			
		||||
                    if (
 | 
			
		||||
                      parseInt(moment(date.startDate).format('YYYYMMDD')) <=
 | 
			
		||||
                        parseInt(moment(currentValue.started).format('YYYYMMDD')) &&
 | 
			
		||||
                      parseInt(moment(currentValue.started).format('YYYYMMDD')) <=
 | 
			
		||||
                        parseInt(moment(date.endDate).format('YYYYMMDD')) &&
 | 
			
		||||
                      currentValue.updateAuthor.displayName === user.username
 | 
			
		||||
                    ) {
 | 
			
		||||
                      return accumulator + currentValue.timeSpentSeconds;
 | 
			
		||||
                    }
 | 
			
		||||
                    return accumulator;
 | 
			
		||||
                  },
 | 
			
		||||
                  0,
 | 
			
		||||
                ) /
 | 
			
		||||
                  60 /
 | 
			
		||||
                  60}
 | 
			
		||||
                h)
 | 
			
		||||
              </Text>
 | 
			
		||||
              {/* Box issue-todo */}
 | 
			
		||||
              <Box display={'flex'} style={{ justifyContent: 'space-between' }}>
 | 
			
		||||
                {/* Box issue */}
 | 
			
		||||
                <Box
 | 
			
		||||
                  w={'50%'}
 | 
			
		||||
                  style={{
 | 
			
		||||
                    border: 'solid 1px gray',
 | 
			
		||||
                    borderRadius: '5px',
 | 
			
		||||
                    padding: '10px',
 | 
			
		||||
                    marginBottom: '5px',
 | 
			
		||||
                    overflowX: 'hidden',
 | 
			
		||||
                    color: '#412d2d',
 | 
			
		||||
                    backgroundColor: '#d1cdce',
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  <Text fw={700} ta={'center'} mb={'5px'}>
 | 
			
		||||
                    WORKLOG
 | 
			
		||||
                  </Text>
 | 
			
		||||
                  {user.information.issues.map((iss) => {
 | 
			
		||||
                    if (
 | 
			
		||||
                      iss.fields.worklog.worklogs.filter(
 | 
			
		||||
                        (w) =>
 | 
			
		||||
                          parseInt(moment(date.startDate).format('YYYYMMDD')) <=
 | 
			
		||||
                            parseInt(moment(w.started).format('YYYYMMDD')) &&
 | 
			
		||||
                          parseInt(moment(date.endDate).format('YYYYMMDD')) >=
 | 
			
		||||
                            parseInt(moment(w.started).format('YYYYMMDD')) &&
 | 
			
		||||
                          w.updateAuthor.displayName === user.username,
 | 
			
		||||
                      ).length > 0
 | 
			
		||||
                    ) {
 | 
			
		||||
                      return (
 | 
			
		||||
                        <Box
 | 
			
		||||
                          key={iss.id}
 | 
			
		||||
                          style={{
 | 
			
		||||
                            border: 'solid 1px gray',
 | 
			
		||||
                            borderRadius: '5px',
 | 
			
		||||
                            boxShadow: '1px 1px 5px 1px gray',
 | 
			
		||||
                            padding: '10px',
 | 
			
		||||
                            marginBottom: '8px',
 | 
			
		||||
                            maxHeight: '90vh',
 | 
			
		||||
                            overflowX: 'hidden',
 | 
			
		||||
                            color: '#412d2d',
 | 
			
		||||
                            backgroundColor: 'white',
 | 
			
		||||
                          }}
 | 
			
		||||
                        >
 | 
			
		||||
                          {/* Box information issue */}
 | 
			
		||||
                          <Box>
 | 
			
		||||
                            <Text
 | 
			
		||||
                              fz={14}
 | 
			
		||||
                              display={'flex'}
 | 
			
		||||
                              style={{ alignItems: 'start' }}
 | 
			
		||||
                            >
 | 
			
		||||
                              <b>Summary:</b>{' '}
 | 
			
		||||
                              <Box
 | 
			
		||||
                                display={'flex'}
 | 
			
		||||
                                style={{ alignItems: 'center' }}
 | 
			
		||||
                              >
 | 
			
		||||
                                <Avatar
 | 
			
		||||
                                  src={iss.fields.project?.avatarUrls['16x16']}
 | 
			
		||||
                                  size={'xs'}
 | 
			
		||||
                                  m={'0 5px'}
 | 
			
		||||
                                />
 | 
			
		||||
                                <Text fz={14} mr={'xs'}>
 | 
			
		||||
                                  {iss.fields.project.name}
 | 
			
		||||
                                </Text>
 | 
			
		||||
                              </Box>
 | 
			
		||||
                              <a
 | 
			
		||||
                                href={`https://apactechvn.atlassian.net/browse/${iss.key}`}
 | 
			
		||||
                                target="_blank"
 | 
			
		||||
                              >
 | 
			
		||||
                                {iss.fields.summary}
 | 
			
		||||
                              </a>
 | 
			
		||||
                            </Text>
 | 
			
		||||
                            <Text fz={14}>
 | 
			
		||||
                              <b>Estimate:</b>{' '}
 | 
			
		||||
                              {iss.fields.timeoriginalestimate / 60 / 60}h
 | 
			
		||||
                            </Text>
 | 
			
		||||
                            <Text fz={14}>
 | 
			
		||||
                              <b>Total time spent:</b>{' '}
 | 
			
		||||
                              {iss.fields.timespent / 60 / 60}h
 | 
			
		||||
                            </Text>
 | 
			
		||||
                            <Text fz={14}>
 | 
			
		||||
                              <b>Time spent <span style={{fontSize:"11px"}}>({date.startDate === date.endDate ? date.startDate : date.startDate+" to "+date.endDate})</span>:</b>
 | 
			
		||||
                              {' '}{iss.fields.worklog.worklogs?.reduce(
 | 
			
		||||
                                (
 | 
			
		||||
                                  accumulator: number,
 | 
			
		||||
                                  currentValue: WorkLog,
 | 
			
		||||
                                ) => {
 | 
			
		||||
                                  if (
 | 
			
		||||
                                    parseInt(
 | 
			
		||||
                                      moment(date.startDate).format('YYYYMMDD'),
 | 
			
		||||
                                    ) <=
 | 
			
		||||
                                      parseInt(
 | 
			
		||||
                                        moment(currentValue.started).format(
 | 
			
		||||
                                          'YYYYMMDD',
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ) &&
 | 
			
		||||
                                    parseInt(
 | 
			
		||||
                                      moment(currentValue.started).format(
 | 
			
		||||
                                        'YYYYMMDD',
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ) <=
 | 
			
		||||
                                      parseInt(
 | 
			
		||||
                                        moment(date.endDate).format('YYYYMMDD'),
 | 
			
		||||
                                      ) &&
 | 
			
		||||
                                    currentValue.updateAuthor.displayName ===
 | 
			
		||||
                                      user.username
 | 
			
		||||
                                  ) {
 | 
			
		||||
                                    return (
 | 
			
		||||
                                      accumulator +
 | 
			
		||||
                                      currentValue.timeSpentSeconds
 | 
			
		||||
                                    )
 | 
			
		||||
                                  }
 | 
			
		||||
                                  return accumulator
 | 
			
		||||
                                },
 | 
			
		||||
                                0,
 | 
			
		||||
                              ) /
 | 
			
		||||
                                60 /
 | 
			
		||||
                                60}
 | 
			
		||||
                              h
 | 
			
		||||
                            </Text>
 | 
			
		||||
                          </Box>
 | 
			
		||||
                          {iss.fields.worklog.worklogs?.map((log, index) => {
 | 
			
		||||
                            if (
 | 
			
		||||
                              moment(date.startDate).format('YYYYMMDD') <=
 | 
			
		||||
                                moment(log.started).format('YYYYMMDD') &&
 | 
			
		||||
                              moment(log.started).format('YYYYMMDD') <=
 | 
			
		||||
                                moment(date.endDate).format('YYYYMMDD') &&
 | 
			
		||||
                              log.updateAuthor.displayName === user.username
 | 
			
		||||
                            ) {
 | 
			
		||||
                              return (
 | 
			
		||||
                                // Box worklog
 | 
			
		||||
                                <Box
 | 
			
		||||
                                  key={index}
 | 
			
		||||
                                  style={{
 | 
			
		||||
                                    padding: '4px 8px',
 | 
			
		||||
                                    marginBottom: '5px',
 | 
			
		||||
                                    marginLeft: '10px',
 | 
			
		||||
                                    backgroundColor: '#d9d9d9',
 | 
			
		||||
                                  }}
 | 
			
		||||
                                >
 | 
			
		||||
                                  <Text fz={13}>
 | 
			
		||||
                                    <b>Start date:</b>{' '}
 | 
			
		||||
                                    {moment(log.started).format(
 | 
			
		||||
                                      'HH:mm YYYY/MM/DD',
 | 
			
		||||
                                    )}
 | 
			
		||||
                                  </Text>
 | 
			
		||||
                                  <Text fz={13}>
 | 
			
		||||
                                    <b>Time spent:</b> {log.timeSpent}
 | 
			
		||||
                                  </Text>
 | 
			
		||||
                                  {log?.comment &&
 | 
			
		||||
                                    log?.comment?.content[0]?.content[0]
 | 
			
		||||
                                      ?.text && (
 | 
			
		||||
                                      <Text fz={13}>
 | 
			
		||||
                                        <b>Comment:</b>{' '}
 | 
			
		||||
                                        {log?.comment &&
 | 
			
		||||
                                          log?.comment?.content[0]?.content[0]
 | 
			
		||||
                                            ?.text}
 | 
			
		||||
                                      </Text>
 | 
			
		||||
                                    )}
 | 
			
		||||
                                </Box>
 | 
			
		||||
                              )
 | 
			
		||||
                            }
 | 
			
		||||
                          })}
 | 
			
		||||
                        </Box>
 | 
			
		||||
                      )
 | 
			
		||||
                    }
 | 
			
		||||
                  })}
 | 
			
		||||
                </Box>
 | 
			
		||||
                {/* Box todo */}
 | 
			
		||||
                <Box
 | 
			
		||||
                  w={'49%'}
 | 
			
		||||
                  style={{
 | 
			
		||||
                    border: 'solid 1px gray',
 | 
			
		||||
                    borderRadius: '5px',
 | 
			
		||||
                    padding: '10px',
 | 
			
		||||
                    marginBottom: '5px',
 | 
			
		||||
                    overflowX: 'hidden',
 | 
			
		||||
                    color: '#412d2d',
 | 
			
		||||
                    backgroundColor: '#f9ffa47a',
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  <Text fw={700} ta={'center'} mb={'5px'}>
 | 
			
		||||
                    ASSIGNMENT
 | 
			
		||||
                  </Text>
 | 
			
		||||
                  {user.tasksAssign.issues?.map((iss, index) => {
 | 
			
		||||
                );
 | 
			
		||||
                return total + totalSpent;
 | 
			
		||||
              }, 0) /
 | 
			
		||||
                60 /
 | 
			
		||||
                60}
 | 
			
		||||
              h)
 | 
			
		||||
            </Text>
 | 
			
		||||
            {/* Box issue-todo */}
 | 
			
		||||
            <Box display={'flex'} style={{ justifyContent: 'space-between', flexWrap: 'wrap' }}>
 | 
			
		||||
              {/* Box issue */}
 | 
			
		||||
              <Box
 | 
			
		||||
                w={{ base: '100%', md: '50%' }}
 | 
			
		||||
                style={{
 | 
			
		||||
                  border: 'solid 1px gray',
 | 
			
		||||
                  borderRadius: '5px',
 | 
			
		||||
                  padding: '10px',
 | 
			
		||||
                  marginBottom: '5px',
 | 
			
		||||
                  overflowX: 'hidden',
 | 
			
		||||
                  color: '#412d2d',
 | 
			
		||||
                  backgroundColor: '#d1cdce',
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <Text fw={700} ta={'center'} mb={'5px'}>
 | 
			
		||||
                  WORKLOG
 | 
			
		||||
                </Text>
 | 
			
		||||
                {user.information.issues.map((iss) => {
 | 
			
		||||
                  if (
 | 
			
		||||
                    iss.fields.worklog.worklogs.filter(
 | 
			
		||||
                      (w) =>
 | 
			
		||||
                        parseInt(moment(date.startDate).format('YYYYMMDD')) <=
 | 
			
		||||
                          parseInt(moment(w.started).format('YYYYMMDD')) &&
 | 
			
		||||
                        parseInt(moment(date.endDate).format('YYYYMMDD')) >=
 | 
			
		||||
                          parseInt(moment(w.started).format('YYYYMMDD')) &&
 | 
			
		||||
                        w.updateAuthor.displayName === user.username,
 | 
			
		||||
                    ).length > 0
 | 
			
		||||
                  ) {
 | 
			
		||||
                    return (
 | 
			
		||||
                      <Box
 | 
			
		||||
                        key={index}
 | 
			
		||||
                        key={iss.id}
 | 
			
		||||
                        style={{
 | 
			
		||||
                          border: 'solid 1px gray',
 | 
			
		||||
                          borderRadius: '5px',
 | 
			
		||||
                          boxShadow: '1px 1px 5px 1px gray',
 | 
			
		||||
                          padding: '10px',
 | 
			
		||||
                          marginBottom: '5px',
 | 
			
		||||
                          marginBottom: '8px',
 | 
			
		||||
                          maxHeight: '90vh',
 | 
			
		||||
                          overflowX: 'hidden',
 | 
			
		||||
                          color: '#412d2d',
 | 
			
		||||
                          backgroundColor: 'white',
 | 
			
		||||
                        }}
 | 
			
		||||
                      >
 | 
			
		||||
                        <Box display={'flex'} style={{ alignItems: 'center' }}>
 | 
			
		||||
                          <Avatar
 | 
			
		||||
                            src={iss.fields.project?.avatarUrls['16x16']}
 | 
			
		||||
                            size={'xs'}
 | 
			
		||||
                            m={'0 5px 0 0'}
 | 
			
		||||
                          />
 | 
			
		||||
                          <Text fz={14} mr={'xs'}>
 | 
			
		||||
                            {iss.fields.project.name}
 | 
			
		||||
                        {/* Box information issue */}
 | 
			
		||||
                        <Box>
 | 
			
		||||
                          <Text fz={14} c={iss.fields.status.statusCategory.colorName}>
 | 
			
		||||
                            <b>{iss.fields.status.name}</b>
 | 
			
		||||
                          </Text>
 | 
			
		||||
                          <Text fz={14} display={'flex'} style={{ alignItems: 'start' }}>
 | 
			
		||||
                            <b>Summary:</b>{' '}
 | 
			
		||||
                            <Box display={'flex'} style={{ alignItems: 'center' }}>
 | 
			
		||||
                              <Avatar
 | 
			
		||||
                                src={iss.fields.project?.avatarUrls['16x16']}
 | 
			
		||||
                                size={'xs'}
 | 
			
		||||
                                m={'0 5px'}
 | 
			
		||||
                              />
 | 
			
		||||
                              <Text fz={14} mr={'xs'}>
 | 
			
		||||
                                {iss.fields.project.name}
 | 
			
		||||
                              </Text>
 | 
			
		||||
                            </Box>
 | 
			
		||||
                            <a href={`https://apactechvn.atlassian.net/browse/${iss.key}`} target="_blank">
 | 
			
		||||
                              {iss.fields.summary}
 | 
			
		||||
                            </a>
 | 
			
		||||
                          </Text>
 | 
			
		||||
                          <Text fz={14}>
 | 
			
		||||
                            <b>Estimate:</b> {iss.fields.timeoriginalestimate / 60 / 60}h
 | 
			
		||||
                          </Text>
 | 
			
		||||
                          <Text fz={14}>
 | 
			
		||||
                            <b>Total time spent:</b> {iss.fields.timespent / 60 / 60}h
 | 
			
		||||
                          </Text>
 | 
			
		||||
                          <Text fz={14}>
 | 
			
		||||
                            <b>
 | 
			
		||||
                              Time spent{' '}
 | 
			
		||||
                              <span style={{ fontSize: '11px' }}>
 | 
			
		||||
                                (
 | 
			
		||||
                                {date.startDate === date.endDate
 | 
			
		||||
                                  ? date.startDate
 | 
			
		||||
                                  : date.startDate + ' to ' + date.endDate}
 | 
			
		||||
                                )
 | 
			
		||||
                              </span>
 | 
			
		||||
                              :
 | 
			
		||||
                            </b>{' '}
 | 
			
		||||
                            {iss.fields.worklog.worklogs?.reduce(
 | 
			
		||||
                              (accumulator, currentValue) => {
 | 
			
		||||
                                if (
 | 
			
		||||
                                  parseInt(moment(date.startDate).format('YYYYMMDD')) <=
 | 
			
		||||
                                    parseInt(moment(currentValue.started).format('YYYYMMDD')) &&
 | 
			
		||||
                                  parseInt(moment(currentValue.started).format('YYYYMMDD')) <=
 | 
			
		||||
                                    parseInt(moment(date.endDate).format('YYYYMMDD')) &&
 | 
			
		||||
                                  currentValue.updateAuthor.displayName === user.username
 | 
			
		||||
                                ) {
 | 
			
		||||
                                  return accumulator + currentValue.timeSpentSeconds;
 | 
			
		||||
                                }
 | 
			
		||||
                                return accumulator;
 | 
			
		||||
                              },
 | 
			
		||||
                              0,
 | 
			
		||||
                            ) /
 | 
			
		||||
                              60 /
 | 
			
		||||
                              60}
 | 
			
		||||
                            h
 | 
			
		||||
                          </Text>
 | 
			
		||||
                        </Box>
 | 
			
		||||
                        <Text
 | 
			
		||||
                          fz={14}
 | 
			
		||||
                          display={'flex'}
 | 
			
		||||
                          style={{ alignItems: 'start' }}
 | 
			
		||||
                        >
 | 
			
		||||
                          <b style={{ marginRight: '5px' }}>Summary:</b>
 | 
			
		||||
                          <a
 | 
			
		||||
                            href={`https://apactechvn.atlassian.net/browse/${iss.key}`}
 | 
			
		||||
                            target="_blank"
 | 
			
		||||
                          >
 | 
			
		||||
                            {iss.fields.summary}
 | 
			
		||||
                          </a>
 | 
			
		||||
                        </Text>
 | 
			
		||||
                        <Text fz={13}>
 | 
			
		||||
                          <b>Time spent:</b> {iss.fields.timespent / 60 / 60}h
 | 
			
		||||
                        </Text>
 | 
			
		||||
                        <Text fz={13}>
 | 
			
		||||
                          <b>Estimate:</b> {iss.fields.timeoriginalestimate / 60 / 60}h
 | 
			
		||||
                        </Text>
 | 
			
		||||
                        <Text fz={'14'}>
 | 
			
		||||
                          <b style={{ marginRight: '5px' }}>Status:</b>
 | 
			
		||||
                          {iss.fields.status.name}
 | 
			
		||||
                        {iss.fields.worklog.worklogs?.map((log, index) => {
 | 
			
		||||
                          if (
 | 
			
		||||
                            moment(date.startDate).format('YYYYMMDD') <= moment(log.started).format('YYYYMMDD') &&
 | 
			
		||||
                            moment(log.started).format('YYYYMMDD') <= moment(date.endDate).format('YYYYMMDD') &&
 | 
			
		||||
                            log.updateAuthor.displayName === user.username
 | 
			
		||||
                          ) {
 | 
			
		||||
                            return (
 | 
			
		||||
                              // Box worklog
 | 
			
		||||
                              <Box
 | 
			
		||||
                                key={index}
 | 
			
		||||
                                style={{
 | 
			
		||||
                                  padding: '4px 8px',
 | 
			
		||||
                                  marginBottom: '5px',
 | 
			
		||||
                                  marginLeft: '10px',
 | 
			
		||||
                                  backgroundColor: '#d9d9d9',
 | 
			
		||||
                                }}
 | 
			
		||||
                              >
 | 
			
		||||
                                <Text fz={13}>
 | 
			
		||||
                                  <b>Start date:</b> {moment(log.started).format('HH:mm YYYY/MM/DD')}
 | 
			
		||||
                                </Text>
 | 
			
		||||
                                <Text fz={13}>
 | 
			
		||||
                                  <b>Time spent:</b> {log.timeSpent}
 | 
			
		||||
                                </Text>
 | 
			
		||||
                                {log?.comment && log?.comment?.content[0]?.content[0]?.text && (
 | 
			
		||||
                                  <Text fz={13}>
 | 
			
		||||
                                    <b>Comment:</b> {log?.comment?.content[0]?.content[0]?.text}
 | 
			
		||||
                                  </Text>
 | 
			
		||||
                                )}
 | 
			
		||||
                              </Box>
 | 
			
		||||
                            );
 | 
			
		||||
                          }
 | 
			
		||||
                        })}
 | 
			
		||||
                      </Box>
 | 
			
		||||
                    );
 | 
			
		||||
                  }
 | 
			
		||||
                })}
 | 
			
		||||
              </Box>
 | 
			
		||||
              {/* Box todo */}
 | 
			
		||||
              <Box
 | 
			
		||||
                w={{ base: '100%', md: '49%' }}
 | 
			
		||||
                style={{
 | 
			
		||||
                  border: 'solid 1px gray',
 | 
			
		||||
                  borderRadius: '5px',
 | 
			
		||||
                  padding: '10px',
 | 
			
		||||
                  marginBottom: '5px',
 | 
			
		||||
                  overflowX: 'hidden',
 | 
			
		||||
                  color: '#412d2d',
 | 
			
		||||
                  backgroundColor: '#f9ffa47a',
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <Text fw={700} ta={'center'} mb={'5px'}>
 | 
			
		||||
                  ASSIGNMENT
 | 
			
		||||
                </Text>
 | 
			
		||||
                {user.tasksAssign.issues?.map((iss, index) => {
 | 
			
		||||
                  return (
 | 
			
		||||
                    <Box
 | 
			
		||||
                      key={index}
 | 
			
		||||
                      style={{
 | 
			
		||||
                        border: 'solid 1px gray',
 | 
			
		||||
                        borderRadius: '5px',
 | 
			
		||||
                        boxShadow: '1px 1px 5px 1px gray',
 | 
			
		||||
                        padding: '10px',
 | 
			
		||||
                        marginBottom: '5px',
 | 
			
		||||
                        overflowX: 'hidden',
 | 
			
		||||
                        color: '#412d2d',
 | 
			
		||||
                        backgroundColor: 'white',
 | 
			
		||||
                      }}
 | 
			
		||||
                    >
 | 
			
		||||
                      <Box display={'flex'} style={{ alignItems: 'center' }}>
 | 
			
		||||
                        <Avatar
 | 
			
		||||
                          src={iss.fields.project?.avatarUrls['16x16']}
 | 
			
		||||
                          size={'xs'}
 | 
			
		||||
                          m={'0 5px 0 0'}
 | 
			
		||||
                        />
 | 
			
		||||
                        <Text fz={14} mr={'xs'}>
 | 
			
		||||
                          {iss.fields.project.name}
 | 
			
		||||
                        </Text>
 | 
			
		||||
                      </Box>
 | 
			
		||||
                    )
 | 
			
		||||
                  })}
 | 
			
		||||
                </Box>
 | 
			
		||||
                      <Text fz={14} display={'flex'} style={{ alignItems: 'start' }}>
 | 
			
		||||
                        <b style={{ marginRight: '5px' }}>Summary:</b>
 | 
			
		||||
                        <a href={`https://apactechvn.atlassian.net/browse/${iss.key}`} target="_blank">
 | 
			
		||||
                          {iss.fields.summary}
 | 
			
		||||
                        </a>
 | 
			
		||||
                      </Text>
 | 
			
		||||
                      <Text fz={13}>
 | 
			
		||||
                        <b>Time spent:</b> {iss.fields.timespent / 60 / 60}h
 | 
			
		||||
                      </Text>
 | 
			
		||||
                      <Text fz={13}>
 | 
			
		||||
                        <b>Estimate:</b> {iss.fields.timeoriginalestimate / 60 / 60}h
 | 
			
		||||
                      </Text>
 | 
			
		||||
                      <Text fz={14} c={iss.fields.status.statusCategory.colorName}>
 | 
			
		||||
                        <b>{iss.fields.status.name}</b>
 | 
			
		||||
                      </Text>
 | 
			
		||||
                    </Box>
 | 
			
		||||
                  );
 | 
			
		||||
                })}
 | 
			
		||||
              </Box>
 | 
			
		||||
            </Box>
 | 
			
		||||
          ))}
 | 
			
		||||
        </Box>
 | 
			
		||||
          </Box>
 | 
			
		||||
        ))}
 | 
			
		||||
      </Box>
 | 
			
		||||
    </div>
 | 
			
		||||
    </Box>
 | 
			
		||||
  </div>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue