const widgetProvider = props.widgetProvider; const account = props.account || "marketing.sputnik-dao.near"; const apiUrl = `https://api.pikespeak.ai/daos/proposals/${account}`; const apiPolicyUrl = `https://api.pikespeak.ai/daos/policy/${account}`; const publicApiKey = "36f2b87a-7ee6-40d8-80b9-5e68e587a5b5"; const forgeUrl = (apiUrl, params) => apiUrl + Object.keys(params).reduce( (paramString, p) => paramString + `${p}=${params[p]}&`, "?" ); const ProposalContainer = styled.div` margin-top: 40px; min-height: 500px; `; const NoProposal = styled.div` text-align: center; margin-top: 100px; `; const resPerPage = 10; State.init({ offset: 0, lastProposalFetch: [], proposals: [], isLoading: false, types: [], account: account, status: [], fromDate: "", toDate: "", }); const columns = [ { id: "submission_time", label: "Submission time", }, { id: "proposal_id", label: "Proposal Id", }, { id: "status", label: "Status", }, { id: "proposal_type", label: "type", }, ]; const nextPage = () => { State.update({ offset: state.offset + resPerPage }); }; const previousPage = () => { State.update({ offset: state.offset - resPerPage }); }; const GenericTable = ( <Widget src={`${widgetProvider}/widget/generic_table`} props={{ title: `${account} proposals`, columns, data: state.proposals, nextPage, previousPage, offset: state.offset, resPerPage, }} /> ); const fetchPolicy = () => { console.log("FETCH POLICY", apiPolicyUrl); asyncFetch(apiPolicyUrl, { mode: "cors", headers: { "x-api-key": publicApiKey, }, }).then(({ err, body, ok }) => { if (ok) { State.update({ council: body.state.policy.roles.find((r) => r.name === "Council").kind, }); } }); }; const fetchProposal = (params) => { asyncFetch(forgeUrl(apiUrl, params), { mode: "cors", headers: { "x-api-key": publicApiKey, }, }).then(({ err, body, ok }) => { if (ok) { const allProposals = [...state.proposals, ...body]; console.log("all proposals", allProposals); State.update({ lastProposalFetch: body, proposals: allProposals, isLoading: false, }); } }); }; if (!state.proposals.length) { fetchProposal({ limit: resPerPage, offset: 0, proposal_types: state.types, status: state.status, time_start: state.fromDate, time_end: state.toDate, }); fetchPolicy(); } if (state.account != account) { State.update({ proposals: [], account, offset: 0 }); } const fetchMore = () => { if (!state.isLoading) { State.update({ offset: state.offset + resPerPage, isLoading: true }); fetchProposal({ limit: resPerPage, offset: state.offset, proposal_types: state.types, status: state.status, time_start: state.fromDate, time_end: state.toDate, }); } }; const ProposalCards = []; state.proposals.forEach((proposal) => { ProposalCards.push( <Widget src={`${widgetProvider}/widget/NDC-proposal-card`} props={{ proposal, council: state.council, }} /> ); }); const selectType = (types) => { State.update({ proposals: [], offset: 0, types: types, }); }; const typeOptions = [ "Transfer", "Vote", "FunctionCall", "AddBounty", "BountyDone", "AddMemberToRole", "RemoveMemberFromRole", "ChangeConfig", "ChangePolicy", "ChangePolicyUpdateParameters", "ChangePolicyUpdateDefaultVotePolicy", "ChangePolicyRemoveRole", "ChangePolicyAddOrUpdateRole", "FactoryInfoUpdate", "SetStakingContract", "UpgradeRemote", "UpgradeSelf", ].map((t) => { return { value: t, label: t, }; }); const SelectType = ( <Widget src={`${widgetProvider}/widget/NDC-checkbox-list`} props={{ widgetProvider, checkboxes: typeOptions, selectedBoxes: state.types, onChange: selectType, label: "Type", id: "proposal-type-selector", }} /> ); const selectStatus = (status) => { State.update({ status, proposals: [], offset: 0, }); }; const statusOptions = ["Approved", "Rejected", "InProgress", "Expired"].map( (t) => { return { value: t, label: t, }; } ); const SelectStatus = ( <Widget src={`${widgetProvider}/widget/NDC-checkbox-list`} props={{ widgetProvider, checkboxes: statusOptions, selectedBoxes: state.status, onChange: selectStatus, label: "Status", id: "proposal-status-selector", }} /> ); const SelectFromDate = ( <Widget src={`${widgetProvider}/widget/NDC-input`} props={{ widgetProvider, validate: "date", sendInput: (fromDate) => { State.update({ fromDate, proposals: [], offset: 0, }); }, placeholder: "yyyy/mm/dd", label: "From Date", }} /> ); const SelectToDate = ( <Widget src={`${widgetProvider}/widget/NDC-input`} props={{ widgetProvider, validate: "date", sendInput: (toDate) => { State.update({ toDate, proposals: [], offset: 0, }); }, placeholder: "yyyy/mm/dd", label: "To Date", }} /> ); const ProposalInfiniteScroll = ( <Widget src={`${widgetProvider}/widget/proposals_scroll`} props={{ cards: ProposalCards, fetchMore: fetchMore, hasMore: state.lastProposalFetch.length === resPerPage, }} /> ); const getFilters = () => { let filters = [...state.status, ...state.types]; if (state.fromDate.length) { filters.push(`From: ${state.fromDate}`); } if (state.toDate.length) { filters.push(`From: ${state.toDate}`); } return filters; }; const ProposalFilters = ( <Widget src={`${widgetProvider}/widget/NDC-filter-menu`} props={{ widgetProvider, comps: [SelectType, SelectStatus, SelectFromDate, SelectToDate], filters: getFilters(), removeFilter: (filter) => { State.update({ types: [...state.types.filter((t) => t != filter)], status: [...state.status.filter((s) => s != filter)], fromDate: filter.includes(state.fromDate) ? "" : state.fromDate, proposals: [], offset: 0, limit: resPerPage, }); }, resetFilters: () => { State.update({ types: [], status: [], proposals: [], offset: 0, limit: resPerPage, }); }, }} /> ); return ( <ProposalContainer> {ProposalFilters} {state.proposals.length ? ( ProposalInfiniteScroll ) : ( <NoProposal>No proposal found.</NoProposal> )} </ProposalContainer> );