a tool for shared writing and social publishing
1import { 2 Fact, 3 ReplicacheMutators, 4 useEntity, 5 useReplicache, 6} from "src/replicache"; 7import { Replicache } from "replicache"; 8import { useUIState } from "src/useUIState"; 9import { scanIndex } from "src/replicache/utils"; 10import { getBlocksWithType } from "src/hooks/queries/useBlocks"; 11import { focusBlock } from "src/utils/focusBlock"; 12import { ButtonPrimary } from "components/Buttons"; 13import { CloseTiny } from "components/Icons/CloseTiny"; 14 15export const AreYouSure = (props: { 16 entityID: string[] | string; 17 onClick?: () => void; 18 closeAreYouSure: () => void; 19 type: Fact<"block/type">["data"]["value"] | undefined; 20 compact?: boolean; 21}) => { 22 let entities = [props.entityID].flat(); 23 let { rep } = useReplicache(); 24 25 return ( 26 <div 27 className={` 28 w-full 29 flex items-center justify-center 30 ${ 31 !props.compact && 32 `bg-border-light border-2 border-border rounded-lg 33 ${ 34 props.type === "card" 35 ? "h-[104px]" 36 : props.type === "mailbox" 37 ? "h-[92px]" 38 : "h-full" 39 }` 40 }`} 41 > 42 <div 43 className={`flex h-fit justify-center items-center font-bold text-secondary ${props.compact ? "flex-row gap-2 justify-between w-full " : "flex-col py-2 gap-1"}`} 44 > 45 <div className="text-center w-fit"> 46 Delete{" "} 47 {entities.length > 1 ? ( 48 "Blocks" 49 ) : props.type === "card" ? ( 50 <span>Page</span> 51 ) : props.type === "mailbox" ? ( 52 <span>Mailbox and Posts</span> 53 ) : ( 54 <span>Block</span> 55 )} 56 ?{" "} 57 </div> 58 <div className="flex gap-2"> 59 <ButtonPrimary 60 autoFocus 61 compact 62 onClick={async (e) => { 63 e.stopPropagation(); 64 if (rep) await deleteBlock(entities, rep); 65 }} 66 > 67 Delete 68 </ButtonPrimary> 69 <button 70 className="text-accent-1" 71 onClick={() => props.closeAreYouSure()} 72 > 73 {props.compact ? ( 74 <CloseTiny className="mx-2 shrink-0" /> 75 ) : ( 76 "Nevermind" 77 )} 78 </button> 79 </div> 80 </div> 81 </div> 82 ); 83}; 84 85export async function deleteBlock( 86 entities: string[], 87 rep: Replicache<ReplicacheMutators>, 88) { 89 // get what pagess we need to close as a result of deleting this block 90 let pagesToClose = [] as string[]; 91 for (let entity of entities) { 92 let [type] = await rep.query((tx) => 93 scanIndex(tx).eav(entity, "block/type"), 94 ); 95 if (type.data.value === "card") { 96 let [childPages] = await rep?.query( 97 (tx) => scanIndex(tx).eav(entity, "block/card") || [], 98 ); 99 pagesToClose = [childPages?.data.value]; 100 } 101 if (type.data.value === "mailbox") { 102 let [archive] = await rep?.query( 103 (tx) => scanIndex(tx).eav(entity, "mailbox/archive") || [], 104 ); 105 let [draft] = await rep?.query( 106 (tx) => scanIndex(tx).eav(entity, "mailbox/draft") || [], 107 ); 108 pagesToClose = [archive?.data.value, draft?.data.value]; 109 } 110 } 111 112 // the next and previous blocks in the block list 113 // if the focused thing is a page and not a block, return 114 let focusedBlock = useUIState.getState().focusedEntity; 115 let parent = 116 focusedBlock?.entityType === "page" 117 ? focusedBlock.entityID 118 : focusedBlock?.parent; 119 120 if (parent) { 121 let parentType = await rep?.query((tx) => 122 scanIndex(tx).eav(parent, "page/type"), 123 ); 124 if (parentType[0]?.data.value === "canvas") { 125 useUIState 126 .getState() 127 .setFocusedBlock({ entityType: "page", entityID: parent }); 128 useUIState.getState().setSelectedBlocks([]); 129 } else { 130 let siblings = 131 (await rep?.query((tx) => getBlocksWithType(tx, parent))) || []; 132 133 let selectedBlocks = useUIState.getState().selectedBlocks; 134 let firstSelected = selectedBlocks[0]; 135 let lastSelected = selectedBlocks[entities.length - 1]; 136 137 let prevBlock = 138 siblings?.[ 139 siblings.findIndex((s) => s.value === firstSelected?.value) - 1 140 ]; 141 let prevBlockType = await rep?.query((tx) => 142 scanIndex(tx).eav(prevBlock?.value, "block/type"), 143 ); 144 145 let nextBlock = 146 siblings?.[ 147 siblings.findIndex((s) => s.value === lastSelected.value) + 1 148 ]; 149 let nextBlockType = await rep?.query((tx) => 150 scanIndex(tx).eav(nextBlock?.value, "block/type"), 151 ); 152 153 if (prevBlock) { 154 useUIState.getState().setSelectedBlock({ 155 value: prevBlock.value, 156 parent: prevBlock.parent, 157 }); 158 159 focusBlock( 160 { 161 value: prevBlock.value, 162 type: prevBlockType?.[0].data.value, 163 parent: prevBlock.parent, 164 }, 165 { type: "end" }, 166 ); 167 } else { 168 useUIState.getState().setSelectedBlock({ 169 value: nextBlock.value, 170 parent: nextBlock.parent, 171 }); 172 173 focusBlock( 174 { 175 value: nextBlock.value, 176 type: nextBlockType?.[0]?.data.value, 177 parent: nextBlock.parent, 178 }, 179 { type: "start" }, 180 ); 181 } 182 } 183 } 184 185 pagesToClose.forEach((page) => page && useUIState.getState().closePage(page)); 186 await Promise.all( 187 entities.map((entity) => 188 rep?.mutate.removeBlock({ 189 blockEntity: entity, 190 }), 191 ), 192 ); 193}