From 12afe8acd74110820d354790e3f54613a88ceb14 Mon Sep 17 00:00:00 2001 From: Matilde Park Date: Fri, 28 May 2021 16:54:01 -0400 Subject: [PATCH] interface: catch contact-update type mismatch When applying add-group or remove-group updates optimistically, we send our ship resourceFromPath objects, and get back /ship/~name/resource strings. When we apply the update optimistically, we use the former, storing the object in state. This causes interface errors, as it expects the string. Therefore, on both ends we construct the string and dedupe if it comes in after application. Fixes urbit/landscape#917 --- .../src/logic/reducers/contact-update.ts | 53 +++++++++++-------- .../apps/profile/components/ViewProfile.tsx | 3 +- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/pkg/interface/src/logic/reducers/contact-update.ts b/pkg/interface/src/logic/reducers/contact-update.ts index 87692cf2ef..6776dc08a2 100644 --- a/pkg/interface/src/logic/reducers/contact-update.ts +++ b/pkg/interface/src/logic/reducers/contact-update.ts @@ -3,27 +3,6 @@ import _ from 'lodash'; import { reduceState } from '../state/base'; import useContactState, { ContactState } from '../state/contact'; -export const ContactReducer = (json) => { - const data: ContactUpdate = _.get(json, 'contact-update', false); - if (data) { - reduceState(useContactState, data, [ - initial, - add, - remove, - edit, - setPublic - ]); - } - - // TODO: better isolation - const res = _.get(json, 'resource', false); - if (res) { - useContactState.setState({ - nackedContacts: useContactState.getState().nackedContacts.add(`~${res.ship}`) - }); - } -}; - const initial = (json: ContactUpdate, state: ContactState): ContactState => { const data = _.get(json, 'initial', false); if (data) { @@ -65,12 +44,20 @@ export const edit = (json: ContactUpdate, state: ContactState): ContactState => } const value = data['edit-field'][field]; - if(field === 'add-group') { - state.contacts[ship].groups.push(value); + if (typeof value !== 'string') { + state.contacts[ship].groups.push(`/ship/${Object.values(value).join('/')}`); + } else if (!(state.contacts[ship].groups.includes(value))) { + state.contacts[ship].groups.push(value); + } } else if (field === 'remove-group') { + if (typeof value !== 'string') { + state.contacts[ship].groups = + state.contacts[ship].groups.filter(g => g !== `/ship/${Object.values(value).join('/')}`); + } else { state.contacts[ship].groups = state.contacts[ship].groups.filter(g => g !== value); + } } else { state.contacts[ship][field] = value; } @@ -84,3 +71,23 @@ const setPublic = (json: ContactUpdate, state: ContactState): ContactState => { return state; }; +export const ContactReducer = (json) => { + const data: ContactUpdate = _.get(json, 'contact-update', false); + if (data) { + reduceState(useContactState, data, [ + initial, + add, + remove, + edit, + setPublic + ]); + } + + // TODO: better isolation + const res = _.get(json, 'resource', false); + if (res) { + useContactState.setState({ + nackedContacts: useContactState.getState().nackedContacts.add(`~${res.ship}`) + }); + } +}; diff --git a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx index 7c1122f9fb..8afcfc3194 100644 --- a/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx +++ b/pkg/interface/src/views/apps/profile/components/ViewProfile.tsx @@ -56,9 +56,10 @@ export function ViewProfile(props: any): ReactElement { Pinned Groups - {contact?.groups.slice().sort(lengthOrder).map(g => ( + {contact?.groups.slice().sort(lengthOrder).map((g, i) => ( {}} />