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
This commit is contained in:
Matilde Park 2021-05-28 16:54:01 -04:00
parent 7ea6c246ce
commit 12afe8acd7
2 changed files with 32 additions and 24 deletions

View File

@ -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<ContactState, ContactUpdate>(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<ContactState, ContactUpdate>(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}`)
});
}
};

View File

@ -56,9 +56,10 @@ export function ViewProfile(props: any): ReactElement {
<Col gapY={3} mb={3} mt={6} alignItems='flex-start'>
<Text gray>Pinned Groups</Text>
<Col>
{contact?.groups.slice().sort(lengthOrder).map(g => (
{contact?.groups.slice().sort(lengthOrder).map((g, i) => (
<GroupLink
api={api}
key={i}
resource={g}
measure={() => {}}
/>