A reply to a case mail becomes a note on its record
Whatever reads the mailbox publishes on portal.mail.received; portal appends the note after checking the record exists in a bucket this site has and the sender is the address the record itself holds. A note never moves a case: a mailbox is the one door anyone may knock on, so it cannot drive a state machine even if someone forges their way past the checks. The desks show the conversation beside the case. Tested: the address parser, every refusal (a stranger, no address to compare, an empty reply, the same reply twice, an unknown contract), and the whole path through a real JetStream - the note lands, the state does not move, and no event is written. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4fd60293fa
commit
26c1762dfa
+26
-1
@@ -1158,6 +1158,7 @@ fn AlternativeCard(
|
||||
let question_id = question_id.clone();
|
||||
let alt_name = alt_name.clone();
|
||||
let feature_name = feature_name.clone();
|
||||
let _place = place.clone();
|
||||
move |req| {
|
||||
let field_id = format!("{}-{}", field_prefix, req.name);
|
||||
let label_for = field_id.clone();
|
||||
@@ -1329,7 +1330,7 @@ fn AlternativeCard(
|
||||
.value
|
||||
.clone()
|
||||
.filter(|v| !v.is_empty())
|
||||
.unwrap_or_else(|| place.clone());
|
||||
.unwrap_or_else(|| _place.clone());
|
||||
let widget: StoredValue<Option<map::MapWidget>, LocalStorage> =
|
||||
StoredValue::new_local(None);
|
||||
Effect::new(move |_| {
|
||||
@@ -1975,6 +1976,7 @@ fn AnswerRow(
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let submitted_ms = answer.submitted_ms;
|
||||
let notes = answer.notes.clone();
|
||||
let state = answer.state.clone();
|
||||
let item_id = answer.id.clone();
|
||||
let key = (feature_name.clone(), item_id.clone());
|
||||
@@ -2025,6 +2027,29 @@ fn AnswerRow(
|
||||
<span class="answer-state">{state}</span>
|
||||
<span class="answer-time">{format_ms(submitted_ms)}</span>
|
||||
</div>
|
||||
// What the person has written back since, oldest first: the
|
||||
// conversation beside the case, which a desk could not see
|
||||
// before. A note moves nothing, so there is no button here.
|
||||
{(!notes.is_empty())
|
||||
.then(|| {
|
||||
view! {
|
||||
<ol class="answer-notes">
|
||||
<For
|
||||
each=move || notes.clone()
|
||||
key=|note| note.id.clone()
|
||||
children=move |note| {
|
||||
view! {
|
||||
<li class="answer-note">
|
||||
<span class="answer-note-who">{note.from}</span>
|
||||
<span class="answer-note-time">{format_ms(note.received_ms)}</span>
|
||||
<p class="answer-note-text">{note.text}</p>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
/>
|
||||
</ol>
|
||||
}
|
||||
})}
|
||||
<Show when={
|
||||
let available = available.clone();
|
||||
move || !available.is_empty()
|
||||
|
||||
Reference in New Issue
Block a user