From 1a24cce1e07a7b31bcb0d39db3d21dd136fc3ba5 Mon Sep 17 00:00:00 2001 From: elraphty Date: Mon, 18 Sep 2023 19:09:09 +0100 Subject: [PATCH 1/2] added view budget histories component --- db/db.go | 6 ++ db/structs.go | 42 +++++++--- frontend/app/src/components/form/style.ts | 5 +- frontend/app/src/helpers/helpers.ts | 2 + .../widgetViews/OrganizationDetails.tsx | 81 +++++++++++++++++-- frontend/app/src/store/main.ts | 38 ++++++++- handlers/organizations.go | 9 +++ handlers/tribes.go | 1 + routes/organizations.go | 1 + 9 files changed, 165 insertions(+), 20 deletions(-) diff --git a/db/db.go b/db/db.go index 47aa4bfb3..4dbc96fb7 100644 --- a/db/db.go +++ b/db/db.go @@ -1104,6 +1104,12 @@ func (db database) GetOrganizationBudget(org_uuid string) BountyBudget { return ms } +func (db database) GetOrganizationBudgetHistory(org_uuid string) []BudgetHistoryData { + budgetHistory := []BudgetHistoryData{} + db.db.Raw(`SELECT budget.id, budget.org_uuid, budget.amount, budget.created, budget.updated, budget.payment_type, budget.status, sender.unique_name AS sender_name FROM public.budget_histories AS budget LEFT OUTER JOIN public.people AS sender ON budget.sender_pub_key = sender.owner_pub_key WHERE budget.org_uuid = '` + org_uuid + `' ORDER BY budget.created DESC`).Find(&budgetHistory) + return budgetHistory +} + func (db database) AddAndUpdateBudget(budget BudgetStoreData) BudgetHistory { created := budget.Created org_uuid := budget.OrgUuid diff --git a/db/structs.go b/db/structs.go index 58d8a7be3..354e2494a 100644 --- a/db/structs.go +++ b/db/structs.go @@ -445,10 +445,11 @@ type BountyBudget struct { } type BudgetInvoiceRequest struct { - Amount uint `json:"amount"` - SenderPubKey string `json:"sender_pubkey"` - OrgUuid string `json:"org_uuid"` - Websocket_token string `json:"websocket_token,omitempty"` + Amount uint `json:"amount"` + SenderPubKey string `json:"sender_pubkey"` + OrgUuid string `json:"org_uuid"` + PaymentType BudgetPaymentType `json:"payment_type,omitempty"` + Websocket_token string `json:"websocket_token,omitempty"` } type BudgetStoreData struct { @@ -460,14 +461,33 @@ type BudgetStoreData struct { Created *time.Time `json:"created"` } +type BudgetPaymentType string + +const ( + Add BudgetPaymentType = "add" + Withdraw BudgetPaymentType = "withdraw" +) + type BudgetHistory struct { - ID uint `json:"id"` - OrgUuid string `json:"org_uuid"` - Amount uint `json:"amount"` - SenderPubKey string `json:"sender_pubkey"` - Created *time.Time `json:"created"` - Updated *time.Time `json:"updated"` - Status bool `json:"status"` + ID uint `json:"id"` + OrgUuid string `json:"org_uuid"` + Amount uint `json:"amount"` + SenderPubKey string `json:"sender_pubkey"` + Created *time.Time `json:"created"` + Updated *time.Time `json:"updated"` + Status bool `json:"status"` + PaymentType BudgetPaymentType `json:"payment_type"` +} + +type BudgetHistoryData struct { + ID uint `json:"id"` + OrgUuid string `json:"org_uuid"` + Amount uint `json:"amount"` + PaymentType BudgetPaymentType `json:"payment_type"` + Status bool `json:"status"` + SenderName string `json:"sender_name"` + Created *time.Time `json:"created"` + Updated *time.Time `json:"updated"` } type PaymentHistory struct { diff --git a/frontend/app/src/components/form/style.ts b/frontend/app/src/components/form/style.ts index 9a9e14c14..6679ed083 100644 --- a/frontend/app/src/components/form/style.ts +++ b/frontend/app/src/components/form/style.ts @@ -9,13 +9,14 @@ interface WrapProps { } export const Wrap = styled.div` - padding: ${(p: any) => (p?.newDesign ? '28px 0px' : '80px 0px 0px 0px')}; + padding: ${(p: any) => (p?.newDesign ? '28px 0px' : '30px 10px')}; margin-bottom: ${(p: any) => !p?.newDesign && '100px'}; display: flex; height: inherit; flex-direction: column; align-content: center; - min-width: 230px; + min-width: 400px; + max-width: auto; `; interface bottomButtonProps { diff --git a/frontend/app/src/helpers/helpers.ts b/frontend/app/src/helpers/helpers.ts index ccef38d43..bff15426f 100644 --- a/frontend/app/src/helpers/helpers.ts +++ b/frontend/app/src/helpers/helpers.ts @@ -167,6 +167,8 @@ export const userHasRole = (bountyRoles: any[], userRoles: any[], role: Roles): }; export const toCapitalize = (word: string): string => { + if(!word.length) return word; + const wordString = word.split(' '); const capitalizeStrings = wordString.map((w: string) => w[0].toUpperCase() + w.slice(1)); diff --git a/frontend/app/src/people/widgetViews/OrganizationDetails.tsx b/frontend/app/src/people/widgetViews/OrganizationDetails.tsx index 9b6119e90..19e35bf52 100644 --- a/frontend/app/src/people/widgetViews/OrganizationDetails.tsx +++ b/frontend/app/src/people/widgetViews/OrganizationDetails.tsx @@ -10,7 +10,7 @@ import { Button, IconButton } from 'components/common'; import { useIsMobile } from 'hooks/uiHooks'; import { Formik } from 'formik'; import { FormField, validator } from 'components/form/utils'; -import { BountyRoles, Organization, PaymentHistory, Person } from 'store/main'; +import { BountyRoles, BudgetHistory, Organization, PaymentHistory, Person } from 'store/main'; import MaterialIcon from '@material/react-material-icon'; import { userHasRole } from 'helpers'; import { Modal } from '../../components/common'; @@ -153,9 +153,11 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und const [isOpenRoles, setIsOpenRoles] = useState(false); const [isOpenBudget, setIsOpenBudget] = useState(false); const [isOpenHistory, setIsOpenHistory] = useState(false); + const [isOpenBudgetHistory, setIsOpenBudgetHistory] = useState(false); const [usersCount, setUsersCount] = useState(0); const [orgBudget, setOrgBudget] = useState(0); const [paymentsHistory, setPaymentsHistory] = useState([]); + const [budgetsHistory, setBudgetsHistory] = useState([]); const [disableFormButtons, setDisableFormButtons] = useState(false); const [users, setUsers] = useState([]); const [user, setUser] = useState(); @@ -260,6 +262,11 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und setPaymentsHistory(paymentHistories); }, [main]); + const getBudgetHistory = useCallback(async () => { + const budgetHistories = await main.getBudgettHistories(uuid); + setBudgetsHistory(budgetHistories); + }, [main]); + const generateInvoice = async () => { const token = ui.meInfo?.websocketToken; if (token) { @@ -267,7 +274,8 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und amount: amount, sender_pubkey: ui.meInfo?.owner_pubkey ?? '', org_uuid: uuid, - websocket_token: token + websocket_token: token, + payment_type: 'add' }); setLnInvoice(data.response.invoice); @@ -296,6 +304,10 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und setIsOpenHistory(false); }; + const closeBudgetHistoryHandler = () => { + setIsOpenBudgetHistory(false); + }; + const onSubmit = async (body: any) => { setIsLoading(true); @@ -359,6 +371,7 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und // get new organization budget getOrganizationBudget(); + getBudgetHistory(); closeBudgetHandler(); } }; @@ -369,12 +382,14 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und getBountyRoles(); getOrganizationBudget(); getPaymentsHistory(); + getBudgetHistory(); }, [ getOrganizationUsers, getOrganizationUsersCount, getBountyRoles, getOrganizationBudget, - getPaymentsHistory + getPaymentsHistory, + getBudgetHistory ]); useEffect(() => { @@ -429,7 +444,10 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und /> )} {(isOrganizationAdmin || userHasRole(bountyRoles, userRoles, 'VIEW REPORT')) && ( - setIsOpenHistory(true)}>View history + <> + setIsOpenBudgetHistory(true)}>Budget history + setIsOpenHistory(true)}>Payment history + )} @@ -545,8 +563,8 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und style={ item.name === 'github_description' && !values.ticket_url ? { - display: 'none' - } + display: 'none' + } : undefined } /> @@ -733,6 +751,57 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und )} + {isOpenBudgetHistory && ( + + + Budget history + + + + + + + + + + + + {budgetsHistory.map((b: BudgetHistory, i: number) => ( + + + + + + + + ))} + +
SenderAmountTypeStatusDate
{b.sender_name}{b.amount} sats{b.payment_type}{b.status ? 'settled' : 'peending'}{moment(b.created).fromNow()}
+
+
+ )} diff --git a/frontend/app/src/store/main.ts b/frontend/app/src/store/main.ts index f65b796b1..bc2a62537 100644 --- a/frontend/app/src/store/main.ts +++ b/frontend/app/src/store/main.ts @@ -133,6 +133,17 @@ export interface PaymentHistory { created: string; } +export interface BudgetHistory { + id: number; + amount: number; + org_uuid: string; + payment_type: string; + created: string; + updated: string; + sender_name: string; + status: boolean; +} + export interface PersonOffer { person: PersonFlex; title: string; @@ -1541,6 +1552,7 @@ export class MainStore { org_uuid: string; sender_pubkey: string; websocket_token: string; + payment_type: string; }): Promise { try { const data = await api.post( @@ -1549,7 +1561,8 @@ export class MainStore { amount: body.amount, org_uuid: body.org_uuid, sender_pubkey: body.sender_pubkey, - websocket_token: body.websocket_token + websocket_token: body.websocket_token, + payment_type: body.payment_type }, { 'Content-Type': 'application/json' @@ -1815,6 +1828,7 @@ export class MainStore { return r.json(); } catch (e) { + console.log('Error getOrganizationBudget', e); return false; } } @@ -1839,6 +1853,7 @@ export class MainStore { return r; } catch (e) { + console.log('Error makeBountyPayment', e); return false; } } @@ -1858,6 +1873,27 @@ export class MainStore { return r.json(); } catch (e) { + console.log('Error getPaymentHistories', e); + return []; + } + } + + async getBudgettHistories(uuid: string): Promise { + try { + if (!uiStore.meInfo) return []; + const info = uiStore.meInfo; + const r: any = await fetch(`${TribesURL}/organizations/budget/history/${uuid}`, { + method: 'GET', + mode: 'cors', + headers: { + 'x-jwt': info.tribe_jwt, + 'Content-Type': 'application/json' + } + }); + + return r.json(); + } catch (e) { + console.log('Error gettHistories', e); return []; } } diff --git a/handlers/organizations.go b/handlers/organizations.go index dd9a18356..076d71c3d 100644 --- a/handlers/organizations.go +++ b/handlers/organizations.go @@ -374,6 +374,15 @@ func GetOrganizationBudget(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(organizationBudget) } +func GetOrganizationBudgetHistory(w http.ResponseWriter, r *http.Request) { + uuid := chi.URLParam(r, "uuid") + // get the organization budget + organizationBudget := db.DB.GetOrganizationBudgetHistory(uuid) + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(organizationBudget) +} + func GetPaymentHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() pubKeyFromAuth, _ := ctx.Value(auth.ContextKey).(string) diff --git a/handlers/tribes.go b/handlers/tribes.go index 57027dd5e..e44c12381 100644 --- a/handlers/tribes.go +++ b/handlers/tribes.go @@ -556,6 +556,7 @@ func GenerateBudgetInvoice(w http.ResponseWriter, r *http.Request) { var budgetHistoryData = db.BudgetHistory{ Amount: invoice.Amount, OrgUuid: invoice.OrgUuid, + PaymentType: invoice.PaymentType, SenderPubKey: invoice.SenderPubKey, Created: &now, Updated: &now, diff --git a/routes/organizations.go b/routes/organizations.go index 2f85dfb74..9c0edffbe 100644 --- a/routes/organizations.go +++ b/routes/organizations.go @@ -30,6 +30,7 @@ func OrganizationRoutes() chi.Router { r.Get("/users/role/{uuid}/{user}", handlers.GetUserRoles) r.Get("/user", handlers.GetUserOrganizations) r.Get("/budget/{uuid}", handlers.GetOrganizationBudget) + r.Get("/budget/history/{uuid}", handlers.GetOrganizationBudgetHistory) r.Get("/payments/{uuid}", handlers.GetPaymentHistory) }) From a06a08045c75dcf53904be7979a17ca0f6701d48 Mon Sep 17 00:00:00 2001 From: elraphty Date: Mon, 18 Sep 2023 22:03:03 +0100 Subject: [PATCH 2/2] change organization add to deposit --- db/db.go | 2 +- db/structs.go | 14 ++++---------- frontend/app/src/components/form/style.ts | 14 ++++++++++++-- .../src/people/widgetViews/OrganizationDetails.tsx | 12 ++++++------ .../src/people/widgetViews/OrganizationView.tsx | 6 +++--- frontend/app/src/store/main.ts | 1 + 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/db/db.go b/db/db.go index 4dbc96fb7..b09dc5d01 100644 --- a/db/db.go +++ b/db/db.go @@ -1106,7 +1106,7 @@ func (db database) GetOrganizationBudget(org_uuid string) BountyBudget { func (db database) GetOrganizationBudgetHistory(org_uuid string) []BudgetHistoryData { budgetHistory := []BudgetHistoryData{} - db.db.Raw(`SELECT budget.id, budget.org_uuid, budget.amount, budget.created, budget.updated, budget.payment_type, budget.status, sender.unique_name AS sender_name FROM public.budget_histories AS budget LEFT OUTER JOIN public.people AS sender ON budget.sender_pub_key = sender.owner_pub_key WHERE budget.org_uuid = '` + org_uuid + `' ORDER BY budget.created DESC`).Find(&budgetHistory) + db.db.Raw(`SELECT budget.id, budget.org_uuid, budget.amount, budget.created, budget.updated, budget.payment_type, budget.status, budget.sender_pub_key, sender.unique_name AS sender_name FROM public.budget_histories AS budget LEFT OUTER JOIN public.people AS sender ON budget.sender_pub_key = sender.owner_pub_key WHERE budget.org_uuid = '` + org_uuid + `' ORDER BY budget.created DESC`).Find(&budgetHistory) return budgetHistory } diff --git a/db/structs.go b/db/structs.go index 354e2494a..d577cd202 100644 --- a/db/structs.go +++ b/db/structs.go @@ -464,8 +464,8 @@ type BudgetStoreData struct { type BudgetPaymentType string const ( - Add BudgetPaymentType = "add" - Withdraw BudgetPaymentType = "withdraw" + Add BudgetPaymentType = "add" + Deposit BudgetPaymentType = "deposit" ) type BudgetHistory struct { @@ -480,14 +480,8 @@ type BudgetHistory struct { } type BudgetHistoryData struct { - ID uint `json:"id"` - OrgUuid string `json:"org_uuid"` - Amount uint `json:"amount"` - PaymentType BudgetPaymentType `json:"payment_type"` - Status bool `json:"status"` - SenderName string `json:"sender_name"` - Created *time.Time `json:"created"` - Updated *time.Time `json:"updated"` + BudgetHistory + SenderName string `json:"sender_name"` } type PaymentHistory struct { diff --git a/frontend/app/src/components/form/style.ts b/frontend/app/src/components/form/style.ts index 6679ed083..4a5fbb006 100644 --- a/frontend/app/src/components/form/style.ts +++ b/frontend/app/src/components/form/style.ts @@ -9,13 +9,23 @@ interface WrapProps { } export const Wrap = styled.div` - padding: ${(p: any) => (p?.newDesign ? '28px 0px' : '30px 10px')}; + padding: ${(p: any) => (p?.newDesign ? '28px 0px' : '80px 0px 0px 0px')}; margin-bottom: ${(p: any) => !p?.newDesign && '100px'}; display: flex; height: inherit; flex-direction: column; align-content: center; - min-width: 400px; + min-width: 230px; +`; + +export const OrgWrap = styled.div` + padding: ${(p: any) => (p?.newDesign ? '28px 0px' : '30px 20px')}; + margin-bottom: ${(p: any) => !p?.newDesign && '100px'}; + display: flex; + height: inherit; + flex-direction: column; + align-content: center; + min-width: 500px; max-width: auto; `; diff --git a/frontend/app/src/people/widgetViews/OrganizationDetails.tsx b/frontend/app/src/people/widgetViews/OrganizationDetails.tsx index 19e35bf52..ebebbe0d7 100644 --- a/frontend/app/src/people/widgetViews/OrganizationDetails.tsx +++ b/frontend/app/src/people/widgetViews/OrganizationDetails.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import { useStores } from 'store'; -import { Wrap } from 'components/form/style'; +import { OrgWrap, Wrap } from 'components/form/style'; import { EuiGlobalToastList } from '@elastic/eui'; import { InvoiceForm, InvoiceInput, InvoiceLabel } from 'people/utils/style'; import moment from 'moment'; @@ -275,7 +275,7 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und sender_pubkey: ui.meInfo?.owner_pubkey ?? '', org_uuid: uuid, websocket_token: token, - payment_type: 'add' + payment_type: 'deposit' }); setLnInvoice(data.response.invoice); @@ -728,7 +728,7 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und borderRadius: '50%' }} > - + Payment history @@ -748,7 +748,7 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und ))}
-
+ )} {isOpenBudgetHistory && ( @@ -775,7 +775,7 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und borderRadius: '50%' }} > - + Budget history @@ -799,7 +799,7 @@ const OrganizationDetails = (props: { close: () => void; org: Organization | und ))}
-
+ )} diff --git a/frontend/app/src/people/widgetViews/OrganizationView.tsx b/frontend/app/src/people/widgetViews/OrganizationView.tsx index 9b1c7ab50..e9fbb3dd5 100644 --- a/frontend/app/src/people/widgetViews/OrganizationView.tsx +++ b/frontend/app/src/people/widgetViews/OrganizationView.tsx @@ -82,7 +82,7 @@ const Organizations = (props: { person: Person }) => { const isMobile = useIsMobile(); const config = widgetConfigs['organizations']; const formRef = useRef(null); - const isMyProfile = ui?.meInfo?.pubkey == props.person.owner_pubkey; + const isMyProfile = ui?.meInfo?.pubkey == props?.person?.owner_pubkey; const schema = [...config.schema]; @@ -247,8 +247,8 @@ const Organizations = (props: { person: Person }) => { style={ item.name === 'github_description' && !values.ticket_url ? { - display: 'none' - } + display: 'none' + } : undefined } /> diff --git a/frontend/app/src/store/main.ts b/frontend/app/src/store/main.ts index bc2a62537..bcc056a19 100644 --- a/frontend/app/src/store/main.ts +++ b/frontend/app/src/store/main.ts @@ -140,6 +140,7 @@ export interface BudgetHistory { payment_type: string; created: string; updated: string; + sender_pub_key: string; sender_name: string; status: boolean; }