Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions backend/main/models/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type Proposal struct {
Voucher *shared.Voucher `json:"voucher,omitempty"`
Achievements_done bool `json:"achievementsDone"`
TallyMethod string `json:"voteType" validate:"required"`
Quorum *float64 `json:"quorum,omitempty"`
}

type UpdateProposalRequestPayload struct {
Expand Down Expand Up @@ -146,9 +147,10 @@ func (p *Proposal) CreateProposal(db *s.Database) error {
cid,
composite_signatures,
voucher,
tally_method
tally_method,
quorum
)
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
RETURNING id, created_at
`,
p.Community_id,
Expand All @@ -167,6 +169,7 @@ func (p *Proposal) CreateProposal(db *s.Database) error {
p.Composite_signatures,
p.Voucher,
p.TallyMethod,
p.Quorum,
).Scan(&p.ID, &p.Created_at)

return err
Expand Down Expand Up @@ -210,17 +213,19 @@ func (p *Proposal) UpdateDraftProposal(db *s.Database) error {
strategy = COALESCE($3, strategy),
min_balance = COALESCE($4, min_balance),
max_weight = COALESCE($5, max_weight),
start_time = COALESCE($6, start_time),
end_time = COALESCE($7, end_time),
body = COALESCE($8, body),
block_height = COALESCE($9, block_height),
cid = COALESCE($10, cid)
WHERE id = $11
quorum = COALESCE($6, quorum),
start_time = COALESCE($7, start_time),
end_time = COALESCE($8, end_time),
body = COALESCE($9, body),
block_height = COALESCE($10, block_height),
cid = COALESCE($11, cid)
WHERE id = $12
`, p.Name,
p.Choices,
p.Strategy,
p.Min_balance,
p.Max_weight,
p.Quorum,
p.Start_time,
p.End_time,
p.Body,
Expand Down
1 change: 0 additions & 1 deletion backend/main/server/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,6 @@ func (a *App) createProposal(w http.ResponseWriter, r *http.Request) {
var p models.Proposal
p.Community_id = communityId


if err := validatePayload(r.Body, &p); err != nil {
log.Error().Err(err).Msg("Error validating payload")
respondWithError(w, errIncompleteRequest)
Expand Down
8 changes: 4 additions & 4 deletions backend/main/server/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ func (h *Helpers) createProposal(p models.Proposal) (models.Proposal, errorRespo

canUserCreateProposal := community.CanUserCreateProposal(h.A.DB, h.A.FlowAdapter, p.Creator_addr)

if err := handlePermissionErrorr(canUserCreateProposal); err != nilErr {
if err := handlePermissionError(canUserCreateProposal); err != nilErr {
return models.Proposal{}, err
}

Expand Down Expand Up @@ -652,7 +652,7 @@ func (h *Helpers) createDraftProposal(c models.Community, p models.Proposal) (mo
p.Creator_addr,
)

if err := handlePermissionErrorr(canUserCreateProposal); err != nilErr {
if err := handlePermissionError(canUserCreateProposal); err != nilErr {
return models.Proposal{}, err
}

Expand Down Expand Up @@ -729,7 +729,7 @@ func (h *Helpers) updateDraftProposal(p models.Proposal) (models.Proposal, error
p.Creator_addr,
)

if err := handlePermissionErrorr(canUserCreateProposal); err != nilErr {
if err := handlePermissionError(canUserCreateProposal); err != nilErr {
return models.Proposal{}, err
}

Expand All @@ -742,7 +742,7 @@ func (h *Helpers) updateDraftProposal(p models.Proposal) (models.Proposal, error
return p, nilErr
}

func handlePermissionErrorr(result models.CanUserCreateProposalResponse) errorResponse {
func handlePermissionError(result models.CanUserCreateProposalResponse) errorResponse {
// If user doesn't have permission, populate errorResponse
// with reason and error.
if !result.HasPermission {
Expand Down
1 change: 1 addition & 0 deletions backend/migrations/000044_add_quorum_column.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE proposals DROP COLUMN IF EXISTS quorum;
1 change: 1 addition & 0 deletions backend/migrations/000044_add_quorum_column.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE proposals ADD COLUMN quorum float;
30 changes: 27 additions & 3 deletions frontend/packages/client/src/api/proposals.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
API_BASE_URL,
COMMUNITIES_URL,
IPFS_GETWAY,
IPFS_GATEWAY,
PROPOSALS_URL,
} from './constants';
import { checkResponse } from 'utils';
Expand All @@ -20,10 +20,25 @@ export const fetchProposal = async ({ proposalId }) => {
const response = await fetch(url);
const proposal = await checkResponse(response);

const sortedProposalChoices =
let sortedProposalChoices =
proposal.choices?.sort((a, b) => (a.choiceText > b.choiceText ? 1 : -1)) ??
[];

if (proposal.voteType === 'basic') {
// Ensure choices are ordered as For/Against/Abstain for basic voting
const choices = [...sortedProposalChoices];
sortedProposalChoices.forEach((choice) => {
let index = 0;
if (choice.choiceText === 'Against') {
index = 1;
} else if (choice.choiceText === 'Abstain') {
index = 2;
}
choices[index] = choice;
});
sortedProposalChoices = choices;
}

const proposalData = {
...proposal,
choices: sortedProposalChoices.map((choice) => ({
Expand All @@ -32,7 +47,7 @@ export const fetchProposal = async ({ proposalId }) => {
choiceImgUrl: choice.choiceImgUrl,
})),
ipfs: proposal.cid,
ipfsUrl: `${IPFS_GETWAY}/${proposal.cid}`,
ipfsUrl: `${IPFS_GATEWAY}/${proposal.cid}`,
totalVotes: proposal.total_votes,
// this is coming as a string from db but there could be multiple based on design
strategy: proposal.strategy || '-',
Expand All @@ -48,6 +63,15 @@ export const createProposalApiReq = async ({
timestamp,
} = {}) => {
const { communityId, ...proposalData } = proposalPayload;

if (proposalData.voteType === 'basic') {
proposalData.choices = [
{ choiceText: 'For', choiceImgUrl: null },
{ choiceText: 'Against', choiceImgUrl: null },
{ choiceText: 'Abstain', choiceImgUrl: null },
];
}

const url = `${COMMUNITIES_URL}/${communityId}/proposals`;
const fetchOptions = {
method: 'POST',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const Wrapper = ({ children }) => (
</h3>
);

export default function VoteHeader({ status }) {
export default function VoteHeader({ status, voteType = 'single-choice' }) {
// Status: user-voted, invite-to-vote, is-closed
const message = {
'user-voted': (
Expand All @@ -20,7 +20,12 @@ export default function VoteHeader({ status }) {
You successfully voted on this proposal!
</div>
),
'invite-to-vote': <>Rank your vote &#10024;</>,
'invite-to-vote': (
<>
{voteType === 'single-choice' ? 'Cast your vote' : 'Rank your vote'}{' '}
&#10024;
</>
),
'is-closed': <>Voting has ended on this proposal.</>,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,21 @@ const StepTwoSchema = yup.object().shape({
})
),
})
.when('voteType', (voteType, schema) =>
voteType === 'single-choice'
.when('voteType', (voteType, schema) => {
if (voteType === 'basic') return;
return voteType === 'single-choice'
? schema.min(2, 'Please add a choice, minimum amount is two')
: schema.min(3, 'Please add a choice, minimum amount is three')
)
: schema.min(3, 'Please add a choice, minimum amount is three');
})
.unique('value', 'Invalid duplicated option'),
quorum: yup
.string()
.trim()
.matches(/\s+$|^$|(^[0-9]+$)/, 'Quorum threshold must be a valid number')
.when('voteType', (voteType, schema) => {
if (voteType !== 'basic') return;
return schema.required('Quorum threshold is required');
}),
maxWeight: yup
.string()
.trim()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const Preview = ({ stepsData }) => {
}))
: null,
};
console.log(proposal.choices);
return (
<div>
<h1 className="title mt-5 is-3">{name}</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const getStartTimeInterval = (startDateIsToday) => {

const getStartTimeIntervalWithDelay = (date, startDateIsToday) => {
if (startDateIsToday) {
return new Date(Date.now() + 60 * 60 * 1000);
return new Date(Date.now() + 10 * 60 * 1000);
}

const startDateIsTomorrow = date ? isTomorrow(date) : false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export default function BasicVoteExample() {
return (
<>
{['For', 'Against', 'Abstain'].map((text, index) => (
<div
className="is-flex is-align-items-center is-justify-content-left mb-1"
style={{ whiteSpace: 'nowrap', width: 75 }}
key={index}
>
<div
className="rounded-full has-background-grey has-text-white mr-2 is-flex is-align-items-center is-justify-content-center"
style={{ width: 12, height: 12 }}
>
{index === 0 ? (
<span style={{ fontSize: 7, paddingTop: 1 }}>&#x2713;</span>
) : null}
</div>
<span className="smaller-text">{text}</span>
</div>
))}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function ChoiceOptionCreator({
setValue('tabOption', option);
};

if (voteType === 'ranked-choice') {
if (voteType === 'ranked-choice' || voteType === 'basic') {
setTab('text-based');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const TextBasedChoices = ({
remove,
} = useFieldArray({
control,
name: 'choices',
name: fieldName,
focusAppend: true,
});

Expand Down
Loading