Skip to content

Commit

Permalink
refactored the metrics average sum
Browse files Browse the repository at this point in the history
  • Loading branch information
elraphty committed Dec 6, 2023
2 parents 7fb0e88 + 26bf344 commit b1ce47b
Show file tree
Hide file tree
Showing 25 changed files with 310 additions and 206 deletions.
54 changes: 32 additions & 22 deletions db/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/stakwork/sphinx-tribes/utils"
)

var SecondsToDateConversion = 60 * 60 * 24

func (db database) TotalPeopleByDateRange(r PaymentDateRange) int64 {
var count int64
db.db.Model(&Person{}).Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Count(&count)
Expand Down Expand Up @@ -72,51 +74,59 @@ func (db database) BountiesPaidPercentage(r PaymentDateRange) uint {
return 0
}

func (db database) PaidDifferenceSum(r PaymentDateRange) uint {
var sum uint
db.db.Model(&Bounty{}).Where("paid_date_difference != ?",
"").Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Select("SUM(paid_date_difference)").Row().Scan(&sum)
return sum
func (db database) PaidDifference(r PaymentDateRange) []DateDifference {
ms := []DateDifference{}

db.db.Raw(`SELECT EXTRACT(EPOCH FROM (paid_date - TO_TIMESTAMP(created))) as diff FROM public.bounty WHERE paid_date IS NOT NULL AND created >= '` + r.StartDate + `' AND created <= '` + r.EndDate + `' `).Find(&ms)
return ms
}

func (db database) PaidDifferenceCount(r PaymentDateRange) int64 {
var count int64
db.db.Model(&Bounty{}).Where("paid_date_difference != ?",
"").Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Count(&count)
list := db.PaidDifference(r)
count = int64(len(list))
return count
}

func (db database) AveragePaidTime(r PaymentDateRange) uint {
paidSum := DB.PaidDifferenceSum(r)
paidList := DB.PaidDifference(r)
paidCount := DB.PaidDifferenceCount(r)
if paidCount != 0 && paidSum != 0 {
avg := paidSum / uint(paidCount)
avgDays := math.Round(float64(avg))
return uint(avgDays)
var paidSum uint
for _, diff := range paidList {
paidSum = uint(math.Round(diff.Diff))
}
return 0
return CalculateAverageDays(paidCount, paidSum)
}

func (db database) CompletedDifferenceSum(r PaymentDateRange) uint {
var sum uint
db.db.Model(&Bounty{}).Where("completion_date_difference != ?",
"").Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Select("SUM(completion_date_difference)").Row().Scan(&sum)
return sum
func (db database) CompletedDifference(r PaymentDateRange) []DateDifference {
ms := []DateDifference{}

db.db.Raw(`SELECT EXTRACT(EPOCH FROM (completion_date - TO_TIMESTAMP(created))) as diff FROM public.bounty WHERE completion_date IS NOT NULL AND created >= '` + r.StartDate + `' AND created <= '` + r.EndDate + `' `).Find(&ms)
return ms
}

func (db database) CompletedDifferenceCount(r PaymentDateRange) int64 {
var count int64
db.db.Model(&Bounty{}).Where("completion_date_difference != ?",
"").Where("created >= ?", r.StartDate).Where("created <= ?", r.EndDate).Count(&count)
list := db.CompletedDifference(r)
count = int64(len(list))
return count
}

func (db database) AverageCompletedTime(r PaymentDateRange) uint {
paidSum := DB.CompletedDifferenceSum(r)
paidList := DB.CompletedDifference(r)
paidCount := DB.CompletedDifferenceCount(r)
var paidSum uint
for _, diff := range paidList {
paidSum = uint(math.Round(diff.Diff))
}
return CalculateAverageDays(paidCount, paidSum)
}

func CalculateAverageDays(paidCount int64, paidSum uint) uint {
if paidCount != 0 && paidSum != 0 {
avg := paidSum / uint(paidCount)
avgDays := math.Round(float64(avg))
avgSeconds := math.Round(float64(avg))
avgDays := math.Round(avgSeconds / float64(SecondsToDateConversion))
return uint(avgDays)
}
return 0
Expand Down
64 changes: 33 additions & 31 deletions db/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,37 +355,35 @@ type Client struct {
}

type Bounty struct {
ID uint `json:"id"`
OwnerID string `json:"owner_id"`
Paid bool `json:"paid"`
Show bool `gorm:"default:false" json:"show"`
Type string `json:"type"`
Award string `json:"award"`
AssignedHours uint8 `json:"assigned_hours"`
BountyExpires string `json:"bounty_expires"`
CommitmentFee uint64 `json:"commitment_fee"`
Price uint `json:"price"`
Title string `json:"title"`
Tribe string `json:"tribe"`
Assignee string `json:"assignee"`
TicketUrl string `json:"ticket_url"`
OrgUuid string `json:"org_uuid"`
Description string `json:"description"`
WantedType string `json:"wanted_type"`
Deliverables string `json:"deliverables"`
GithubDescription bool `json:"github_description"`
OneSentenceSummary string `json:"one_sentence_summary"`
EstimatedSessionLength string `json:"estimated_session_length"`
EstimatedCompletionDate string `json:"estimated_completion_date"`
Created int64 `json:"created"`
Updated *time.Time `json:"updated"`
AssignedDate *time.Time `json:"assigned_date,omitempty"`
CompletionDate *time.Time `json:"completion_date,omitempty"`
MarkAsPaidDate *time.Time `json:"mark_as_paid_date,omitempty"`
PaidDate *time.Time `json:"paid_date,omitempty"`
PaidDateDifference int64 `gorm:"type:bigint;not null default:'0'" json:"paid_date_difference,omitempty"`
CompletionDateDifference int64 `gorm:"type:bigint;not null default:'0'" json:"completion_date_difference,omitempty"`
CodingLanguages pq.StringArray `gorm:"type:text[];not null default:'[]'" json:"coding_languages"`
ID uint `json:"id"`
OwnerID string `json:"owner_id"`
Paid bool `json:"paid"`
Show bool `gorm:"default:false" json:"show"`
Type string `json:"type"`
Award string `json:"award"`
AssignedHours uint8 `json:"assigned_hours"`
BountyExpires string `json:"bounty_expires"`
CommitmentFee uint64 `json:"commitment_fee"`
Price uint `json:"price"`
Title string `json:"title"`
Tribe string `json:"tribe"`
Assignee string `json:"assignee"`
TicketUrl string `json:"ticket_url"`
OrgUuid string `json:"org_uuid"`
Description string `json:"description"`
WantedType string `json:"wanted_type"`
Deliverables string `json:"deliverables"`
GithubDescription bool `json:"github_description"`
OneSentenceSummary string `json:"one_sentence_summary"`
EstimatedSessionLength string `json:"estimated_session_length"`
EstimatedCompletionDate string `json:"estimated_completion_date"`
Created int64 `json:"created"`
Updated *time.Time `json:"updated"`
AssignedDate *time.Time `json:"assigned_date,omitempty"`
CompletionDate *time.Time `json:"completion_date,omitempty"`
MarkAsPaidDate *time.Time `json:"mark_as_paid_date,omitempty"`
PaidDate *time.Time `json:"paid_date,omitempty"`
CodingLanguages pq.StringArray `gorm:"type:text[];not null default:'[]'" json:"coding_languages"`
}

type BountyData struct {
Expand Down Expand Up @@ -642,6 +640,10 @@ type Meme struct {
Expiry *time.Time `json:"expiry"`
}

type DateDifference struct {
Diff float64 `json:"diff"`
}

type BountyMetrics struct {
BountiesPosted int64 `json:"bounties_posted"`
BountiesPaid int64 `json:"bounties_paid"`
Expand Down
4 changes: 4 additions & 0 deletions frontend/app/src/admin/admin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { observer } from 'mobx-react-lite';
import React from 'react';

export const AdminPage = observer(() => <div>Admin</div>);
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';

import { EuiText } from '@elastic/eui';
import { Box, Stack } from '@mui/system';
import { BaseModal } from '../BaseModal';
import { ReactComponent as CloseIcon } from './close.svg';
import { image } from './image';
export type AlreadyDeletedProps = {
onClose: () => void;
bountyLink?: string;
bountyTitle?: string;
isDeleted: boolean;
};
export const AlreadyDeleted = ({ onClose, bountyTitle }: AlreadyDeletedProps) => {
const closeHandler = () => {
onClose();
};

return (
<BaseModal open onClose={closeHandler}>
<Stack
position="relative"
sx={{
background:
'linear-gradient(0deg, rgba(255,255,255,1) 0%, rgba(255,255,255,1) 50%, rgba(245,246,248,1) 50%, rgba(245,246,248,1) 100%)'
}}
minWidth={350}
width="70vw"
height="100vh"
overflow="auto"
p={1}
alignItems="center"
justifyContent="center"
>
<Box
onClick={closeHandler}
position="absolute"
right="1rem"
top="1rem"
sx={{ cursor: 'pointer' }}
>
<CloseIcon />
</Box>
<Box
position="absolute"
sx={{
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
'& > svg>g': {
boxShadow: ' 0px 1px 20px 0px rgba(0, 0, 0, 0.15)'
}
}}
>
{image}
</Box>
<Stack
zIndex={1}
useFlexGap
alignItems="center"
m="auto"
direction="column"
justifyContent="space-between"
>
<Box
textAlign="center"
color="rgba(142, 150, 156, 1)"
fontSize={36}
lineHeight={1.2}
component={EuiText}
mb={{ xs: '250px', sm: '230px' }}
>
This bounty has been <br />
<Box component="span" fontWeight={700}>
deleted
</Box>
</Box>
<br />
<Box color="rgba(142, 150, 156, 1)" component={EuiText}>
{bountyTitle}
</Box>
</Stack>
</Stack>
</BaseModal>
);
};
17 changes: 13 additions & 4 deletions frontend/app/src/components/form/inputs/MultiSelectInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import styled from 'styled-components';
import { EuiIcon } from '@elastic/eui';
import { MultiSelect } from '../../common';
Expand All @@ -12,7 +12,7 @@ interface styledProps {

const ExtraText = styled.div`
padding: 2px 10px 25px 10px;
max-width: calc(100% - 20px);
max-width: calc(100 % - 20px);
word-break: break-all;
font-size: 14px;
`;
Expand All @@ -25,7 +25,7 @@ const E = styled.div<styledProps>`
height: 100%;
justify-content: center;
align-items: center;
color: ${(p: any) => p.color && p.color.blue3};
color: ${(p: any) => p?.color && p.color.blue3};
pointer-events: none;
user-select: none;
`;
Expand All @@ -46,9 +46,16 @@ export default function MultiSelectInput({
if (error) labeltext = `${labeltext} (${error})`;
const color = colors['light'];

const [isTop, setIsTop] = useState<boolean>(false);

return (
<>
<FieldEnv label={labeltext} color={color}>
<FieldEnv
color={color}
label={labeltext}
isTop={isTop || value?.length > 0}
isFill={value?.length > 0}
>
<R>
<MultiSelect
selectStyle={{ border: 'none' }}
Expand All @@ -57,7 +64,9 @@ export default function MultiSelectInput({
value={value}
onChange={(e: any) => {
handleChange(e);
setIsTop(true);
}}
setIsTop={setIsTop}
/>
{error && (
<E color={color}>
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/components/form/inputs/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export default function TextInput({
handleFocus(e);
setActive(true);
}}
prepend={prepend}
prepend={active ? prepend : ''}
style={padStyle}
isTextField={true}
/>
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/components/form/inputs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const FieldText = styled(EuiFieldText)<styledProps>`
p.readOnly ? `${p.color.grayish.G60A}` : `${p.color.pureBlack}`} !important;
box-shadow: none !important;
height: ${(p: any) => (p?.isTextField ? '12px' : '')};
margin-top: ${(p: any) => (p?.isTextField ? '2px' : '')};
margin-top: ${(p: any) => (p?.isTextField ? '8px' : '')};
.euiFormRow__labelWrapper .euiFormControlLayout--group {
background-color: ${(p: any) => p?.color && p.color.pureWhite} !important;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export interface Extras {
github?: [{ [key: string]: string }];
coding_languages?: [{ [key: string]: string }];
tribes?: [{ [key: string]: string }];
repos?: [{ [key: string]: string }];
lightning?: [{ [key: string]: string }];
amboss?: [{ [key: string]: string }];
}
Expand Down
19 changes: 0 additions & 19 deletions frontend/app/src/components/form/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,6 @@ import { FormField } from './utils';

const strValidator = Yup.string().trim().required('Required');
const strValidatorNotRequired = Yup.string().trim();
const repoStrValidator = Yup.string()
.trim()
.matches(/^[^/]+\/[^/]+$/, 'Incorrect format')
.required('Required');
const repoArrayStrValidator = Yup.array().of(
Yup.object().shape({
value: repoStrValidator
})
);
const badgeObjectStrValidator = Yup.object().shape({
value: strValidator
});
Expand Down Expand Up @@ -434,16 +425,6 @@ export const aboutSchema: FormField[] = [
prepend: 'https://github.com/',
page: 1
},
{
name: 'repos',
label: 'Github Repository Links',
widget: true,
type: 'creatablemultiselect',
options: [],
note: 'Enter in this format: ownerName/repoName, (e.g. stakwork/sphinx-tribes).',
validator: repoArrayStrValidator, // look for 1 slash
page: 1
},
{
name: 'lightning',
label: 'Lightning address',
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/components/form/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const Wrap = styled.div<WrapProps>`
height: inherit;
flex-direction: column;
align-content: center;
min-width: 230px;
min-width: 600px;
`;

export const OrgWrap = styled.div<WrapProps>`
Expand Down
4 changes: 4 additions & 0 deletions frontend/app/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import '@material/react-material-icon/dist/material-icon.css';
import { AppMode } from 'config';
import { Route, Switch } from 'react-router-dom';
import { observer } from 'mobx-react-lite';
import { AdminPage } from 'admin/admin';
import BotsBody from '../bots/Body';
import PeopleHeader from '../people/main/Header';
import TokenRefresh from '../people/utils/TokenRefresh';
Expand Down Expand Up @@ -44,6 +45,9 @@ const modeDispatchPages: Record<AppMode, () => React.ReactElement> = {
<Route path="/leaderboard">
<LeaderboardPage />
</Route>
<Route path="/admin">
<AdminPage />
</Route>
<Route path="*">
<Body />
</Route>
Expand Down
Loading

0 comments on commit b1ce47b

Please sign in to comment.