a tool for shared writing and social publishing

fix tag selector when no draft and tweak search

+68 -36
+21 -8
app/[leaflet_id]/publish/PublishPost.tsx
··· 33 33 record?: PubLeafletPublication.Record; 34 34 posts_in_pub?: number; 35 35 entitiesToDelete?: string[]; 36 + hasDraft: boolean; 36 37 }; 37 38 38 39 export function PublishPost(props: Props) { ··· 67 68 let params = useParams(); 68 69 let { rep } = useReplicache(); 69 70 70 - // Get tags from Replicache state (same as in the draft editor) 71 - let tags = useSubscribe(rep, (tx) => tx.get<string[]>("publication_tags")); 71 + // For publications with drafts, use Replicache; otherwise use local state 72 + let replicacheTags = useSubscribe(rep, (tx) => 73 + tx.get<string[]>("publication_tags"), 74 + ); 75 + let [localTags, setLocalTags] = useState<string[]>([]); 72 76 73 - // Default to empty array if undefined 74 - const currentTags = Array.isArray(tags) ? tags : []; 77 + // Use Replicache tags only when we have a draft 78 + const hasDraft = props.hasDraft; 79 + const currentTags = hasDraft 80 + ? Array.isArray(replicacheTags) 81 + ? replicacheTags 82 + : [] 83 + : localTags; 75 84 76 - // Update tags via the same mutation used in the editor 85 + // Update tags via Replicache mutation or local state depending on context 77 86 const handleTagsChange = async (newTags: string[]) => { 78 - await rep?.mutate.updatePublicationDraft({ 79 - tags: newTags, 80 - }); 87 + if (hasDraft) { 88 + await rep?.mutate.updatePublicationDraft({ 89 + tags: newTags, 90 + }); 91 + } else { 92 + setLocalTags(newTags); 93 + } 81 94 }; 82 95 83 96 async function submit() {
+6
app/[leaflet_id]/publish/page.tsx
··· 99 99 // If parsing fails, just use empty array 100 100 } 101 101 102 + // Check if a draft record exists (either in a publication or standalone) 103 + let hasDraft = 104 + data.leaflets_in_publications.length > 0 || 105 + data.leaflets_to_documents.length > 0; 106 + 102 107 return ( 103 108 <ReplicacheProvider 104 109 rootEntity={rootEntity} ··· 116 121 record={publication?.record as PubLeafletPublication.Record | undefined} 117 122 posts_in_pub={publication?.documents_in_publications[0]?.count} 118 123 entitiesToDelete={entitiesToDelete} 124 + hasDraft={hasDraft} 119 125 /> 120 126 </ReplicacheProvider> 121 127 );
+41 -28
components/Tags.tsx
··· 95 95 [tagInputValue], 96 96 ); 97 97 98 - const filteredTags = searchResults.filter( 99 - (tag) => !props.selectedTags.includes(tag.name), 100 - ); 98 + const filteredTags = searchResults 99 + .filter((tag) => !props.selectedTags.includes(tag.name)) 100 + .filter((tag) => 101 + tag.name.toLowerCase().includes(tagInputValue.toLowerCase()), 102 + ); 103 + 104 + const showResults = tagInputValue.length >= 3; 101 105 102 106 function clearTagInput() { 103 107 setHighlightedIndex(0); ··· 139 143 }; 140 144 141 145 const userInputResult = 146 + showResults && 142 147 tagInputValue !== "" && 143 148 !filteredTags.some((tag) => tag.name === tagInputValue); 144 149 ··· 219 224 )} 220 225 <hr className=" mb-[2px] border-border-light" /> 221 226 222 - {userInputResult && ( 227 + {showResults ? ( 223 228 <> 224 - <TagResult 225 - key={"userInput"} 226 - index={0} 227 - name={tagInputValue} 228 - tagged={0} 229 - highlighted={0 === highlightedIndex} 230 - setHighlightedIndex={setHighlightedIndex} 231 - onSelect={() => { 232 - selectTag(tagInputValue); 233 - }} 234 - /> 229 + {userInputResult && ( 230 + <TagResult 231 + key={"userInput"} 232 + index={0} 233 + name={tagInputValue} 234 + tagged={0} 235 + highlighted={0 === highlightedIndex} 236 + setHighlightedIndex={setHighlightedIndex} 237 + onSelect={() => { 238 + selectTag(tagInputValue); 239 + }} 240 + /> 241 + )} 242 + {filteredTags.map((tag, i) => ( 243 + <TagResult 244 + key={tag.name} 245 + index={userInputResult ? i + 1 : i} 246 + name={tag.name} 247 + tagged={tag.document_count} 248 + highlighted={ 249 + (userInputResult ? i + 1 : i) === highlightedIndex 250 + } 251 + setHighlightedIndex={setHighlightedIndex} 252 + onSelect={() => { 253 + selectTag(tag.name); 254 + }} 255 + /> 256 + ))} 235 257 </> 258 + ) : ( 259 + <div className="text-tertiary italic text-sm py-1"> 260 + type at least 3 characters to search 261 + </div> 236 262 )} 237 - {filteredTags.map((tag, i) => ( 238 - <TagResult 239 - key={tag.name} 240 - index={userInputResult ? i + 1 : i} 241 - name={tag.name} 242 - tagged={tag.document_count} 243 - highlighted={(userInputResult ? i + 1 : i) === highlightedIndex} 244 - setHighlightedIndex={setHighlightedIndex} 245 - onSelect={() => { 246 - selectTag(tag.name); 247 - }} 248 - /> 249 - ))} 250 263 </div> 251 264 </Popover> 252 265 </div>