Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2414 - "See proposal" link should always lead to proposal #2421

Merged
merged 4 commits into from
Dec 10, 2024
Merged
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
10 changes: 10 additions & 0 deletions frontend/controller/actions/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
JOINED_CHATROOM,
LEFT_GROUP,
LOGOUT,
OPEN_MODAL,
REPLACE_MODAL
} from '@utils/events.js'
import { imageUpload } from '@utils/image.js'
Expand Down Expand Up @@ -920,6 +921,15 @@ export default (sbp('sbp/selectors/register', {
sbp('okTurtles.events/emit', REPLACE_MODAL, 'IncomeDetails')
}
},
'gi.actions/group/checkAndSeeProposal': function ({ data }: GIActionParams) {
const openProposalIds = Object.keys(sbp('state/vuex/getters').currentGroupState.proposals || {})

if (openProposalIds.includes(data.proposalHash)) {
sbp('controller/router').push({ path: '/dashboard#proposals' })
} else {
sbp('okTurtles.events/emit', OPEN_MODAL, 'PropositionsAllModal', { targetProposal: data.proposalHash })
}
},
'gi.actions/group/fixAnyoneCanJoinLink': function ({ contractID }) {
// Queue ensures that the update happens as atomically as possible
return sbp('chelonia/queueInvocation', `${contractID}-FIX-ANYONE-CAN-JOIN`, async () => {
Expand Down
7 changes: 4 additions & 3 deletions frontend/model/contracts/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ sbp('chelonia/defineContract', {
// TODO: create a global timer to auto-pass/archive expired votes
// make sure to set that proposal's status as STATUS_EXPIRED if it's expired
},
sideEffect ({ contractID, meta, data, height, innerSigningContractID }, { getters }) {
sideEffect ({ contractID, meta, hash, data, height, innerSigningContractID }, { getters }) {
const { loggedIn } = sbp('state/vuex/state')
const typeToSubTypeMap = {
[PROPOSAL_INVITE_MEMBER]: 'ADD_MEMBER',
Expand All @@ -702,6 +702,7 @@ sbp('chelonia/defineContract', {
createdDate: meta.createdDate,
groupID: contractID,
creatorID: innerSigningContractID,
proposalHash: hash,
subtype: typeToSubTypeMap[data.proposalType]
})
}
Expand Down Expand Up @@ -1545,10 +1546,10 @@ sbp('chelonia/defineContract', {
await sbp('gi.db/archive/delete', archPaymentsByPeriodKey)
await sbp('gi.db/archive/delete', archSentOrReceivedPaymentsKey)
},
'gi.contracts/group/makeNotificationWhenProposalClosed': function (state, contractID, meta, height, proposal) {
'gi.contracts/group/makeNotificationWhenProposalClosed': function (state, contractID, meta, height, proposalHash, proposal) {
const { loggedIn } = sbp('state/vuex/state')
if (isActionNewerThanUserJoinedDate(height, state.profiles[loggedIn.identityContractID])) {
sbp('gi.notifications/emit', 'PROPOSAL_CLOSED', { createdDate: meta.createdDate, groupID: contractID, proposal })
sbp('gi.notifications/emit', 'PROPOSAL_CLOSED', { createdDate: meta.createdDate, groupID: contractID, proposalHash, proposal })
}
},
'gi.contracts/group/sendMincomeChangedNotification': async function (contractID, meta, data, height, innerSigningContractID) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/model/contracts/shared/voting/proposals.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function notifyAndArchiveProposal ({ state, proposalHash, proposal, contr
// because we remove the state.proposals[proposalHash] in the process function
// and can not access the proposal data in the sideEffect
sbp('gi.contracts/group/pushSideEffect', contractID,
['gi.contracts/group/makeNotificationWhenProposalClosed', state, contractID, meta, height, proposal]
['gi.contracts/group/makeNotificationWhenProposalClosed', state, contractID, meta, height, proposalHash, proposal]
)
sbp('gi.contracts/group/pushSideEffect', contractID,
['gi.contracts/group/archiveProposal', contractID, proposalHash, proposal]
Expand Down
25 changes: 17 additions & 8 deletions frontend/model/notifications/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export default ({
scope: 'group'
}
},
NEW_PROPOSAL (data: { groupID: string, creatorID: string, subtype: NewProposalType }) {
NEW_PROPOSAL (data: { groupID: string, creatorID: string, proposalHash: string, subtype: NewProposalType }) {
const args = {
name: `${CHATROOM_MEMBER_MENTION_SPECIAL_CHAR}${data.creatorID}`,
...LTags('strong')
Expand Down Expand Up @@ -173,9 +173,12 @@ export default ({
creatorID: data.creatorID,
icon: iconMap[data.subtype],
level: 'info',
linkTo: '/dashboard#proposals',
subtype: data.subtype,
scope: 'group'
scope: 'group',
sbpInvocation: ['gi.actions/group/checkAndSeeProposal', {
contractID: sbp('state/vuex/state').currentGroupId,
data: { proposalHash: data.proposalHash }
}]
}
},
PROPOSAL_EXPIRING (data: { proposalId: string, proposal: Object }) {
Expand All @@ -200,11 +203,14 @@ export default ({
level: 'info',
icon: 'exclamation-triangle',
scope: 'group',
linkTo: '/dashboard#proposals',
data: { proposalId: data.proposalId }
data: { proposalId: data.proposalId },
sbpInvocation: ['gi.actions/group/checkAndSeeProposal', {
contractID: sbp('state/vuex/state').currentGroupId,
data: { proposalHash: data.proposalId }
}]
}
},
PROPOSAL_CLOSED (data: { proposal: Object }) {
PROPOSAL_CLOSED (data: { proposal: Object, proposalHash: string }) {
const { creatorID, status, type, options } = getProposalDetails(data.proposal)

const statusMap = {
Expand Down Expand Up @@ -244,8 +250,11 @@ export default ({
body: bodyTemplateMap[type],
icon: statusMap[status].icon,
level: statusMap[status].level,
linkTo: '/dashboard#proposals',
scope: 'group'
scope: 'group',
sbpInvocation: ['gi.actions/group/checkAndSeeProposal', {
contractID: sbp('state/vuex/state').currentGroupId,
data: { proposalHash: data.proposalHash }
}]
}
},
PAYMENT_RECEIVED (data: { creatorID: string, amount: string, paymentHash: string }) {
Expand Down
18 changes: 16 additions & 2 deletions frontend/views/containers/chatroom/MessageInteractive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ message-base(v-bind='$props' @wrapperAction='action')
template(#body='')
.c-text
render-message-text(:text='interactiveMessage.text')
i18n.c-link(@click='$router.push({ path: "/dashboard#proposals" })') See proposal
i18n.c-link(@click='onSeeProposalClick') See proposal
</template>

<script>
import sbp from '@sbp/sbp'
import { mapGetters } from 'vuex'
import { L } from '@common/common.js'
import {
Expand All @@ -31,6 +32,7 @@ import {
STATUS_EXPIRED,
STATUS_CANCELLED
} from '@model/contracts/shared/constants.js'
import { OPEN_MODAL } from '@utils/events.js'
import { getProposalDetails } from '@model/contracts/shared/functions.js'
import MessageBase from './MessageBase.vue'
import RenderMessageText from './chat-mentions/RenderMessageText.vue'
Expand Down Expand Up @@ -143,10 +145,22 @@ export default ({
humanDate,
action () {
console.log('TODO')
},
onSeeProposalClick () {
const openProposalIds = Object.keys(this.currentGroupState.proposals)

if (openProposalIds.includes(this.proposal.proposalId)) { // the proposal is currently active
this.$router.push({ path: '/dashboard#proposals' })
} else { // the proposal has been archived
sbp('okTurtles.events/emit', OPEN_MODAL, 'PropositionsAllModal', { targetProposal: this.proposal.proposalId })
}
}
},
computed: {
...mapGetters(['userDisplayNameFromID']),
...mapGetters([
'currentGroupState',
'userDisplayNameFromID'
]),
interactiveMessage () {
const { status, creatorID } = this.proposal
const baseOptions = { from: `${CHATROOM_MEMBER_MENTION_SPECIAL_CHAR}${creatorID}` }
Expand Down
2 changes: 1 addition & 1 deletion frontend/views/containers/proposals/ProposalItem.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template lang='pug'>
li.c-item-wrapper(data-test='proposalItem')
li.c-item-wrapper(data-test='proposalItem' :data-proposal-hash='proposalHash')
.c-item
.c-main
.c-icons
Expand Down
15 changes: 14 additions & 1 deletion frontend/views/containers/proposals/PropositionsAllModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ modal-base-template.has-background(ref='modal' :fullscreen='true' :a11yTitle='L(
option(value='Oldest') {{ L('Oldest first') }}

.card.c-card
ul(data-test='proposalsWidget')
ul(data-test='proposalsWidget' ref='pList')
proposal-item(
v-for='[hash, obj] of proposals'
:key='hash'
Expand Down Expand Up @@ -55,10 +55,23 @@ export default ({
async mounted () {
const key = `proposals/${this.ourIdentityContractId}/${this.currentGroupId}`
this.ephemeral.proposals = await sbp('gi.db/archive/load', key) || []

this.checkTargetAndScroll()
},
methods: {
unfocusSelect () {
this.$refs.select.blur()
},
checkTargetAndScroll () {
const targetId = this.$route.query?.targetProposal || ''

if (targetId && this.ephemeral.proposals.some(entry => entry[0] === targetId)) {
this.$nextTick(() => {
const targetEl = this.$refs.pList.querySelector(`[data-proposal-hash="${targetId}"]`)

targetEl && targetEl.scrollIntoView({ block: 'center' })
})
}
}
},
computed: {
Expand Down