feat: add confirmation prompts for creating new follow and mute lists

This commit is contained in:
codytseng
2025-08-13 23:23:10 +08:00
parent 71cf05c820
commit 9c3d9a5432
17 changed files with 101 additions and 16 deletions

View File

@@ -333,6 +333,10 @@ export default {
'No zaps yet': 'لا توجد زابس بعد',
'No more reposts': 'لا توجد مزيد من إعادة النشر',
'No reposts yet': 'لا توجد إعادة نشر بعد',
Reposts: 'إعادة النشر'
Reposts: 'إعادة النشر',
FollowListNotFoundConfirmation:
'لم يتم العثور على قائمة المتابعة. هل تريد إنشاء واحدة جديدة؟ إذا كنت قد تابعت مستخدمين من قبل، يرجى عدم التأكيد لأن هذه العملية ستؤدي إلى فقدان قائمة المتابعة السابقة.',
MuteListNotFoundConfirmation:
'لم يتم العثور على قائمة الكتم. هل تريد إنشاء واحدة جديدة؟ إذا كنت قد كتمت مستخدمين من قبل، يرجى عدم التأكيد لأن هذه العملية ستؤدي إلى فقدان قائمة الكتم السابقة.'
}
}

View File

@@ -340,6 +340,10 @@ export default {
'No zaps yet': 'Noch keine Zaps',
'No more reposts': 'Keine weiteren Reposts',
'No reposts yet': 'Noch keine Reposts',
Reposts: 'Reposts'
Reposts: 'Reposts',
FollowListNotFoundConfirmation:
'Folgeliste nicht gefunden. Möchten Sie eine neue erstellen? Wenn Sie zuvor Benutzer gefolgt haben, bestätigen Sie bitte NICHT, da diese Operation dazu führt, dass Sie Ihre vorherige Folgeliste verlieren.',
MuteListNotFoundConfirmation:
'Stummschaltungsliste nicht gefunden. Möchten Sie eine neue erstellen? Wenn Sie zuvor Benutzer stummgeschaltet haben, bestätigen Sie bitte NICHT, da diese Operation dazu führt, dass Sie Ihre vorherige Stummschaltungsliste verlieren.'
}
}

View File

@@ -334,6 +334,10 @@ export default {
'No zaps yet': 'No zaps yet',
'No more reposts': 'No more reposts',
'No reposts yet': 'No reposts yet',
Reposts: 'Reposts'
Reposts: 'Reposts',
FollowListNotFoundConfirmation:
'Follow list not found. Do you want to create a new one? If you have followed users before, please DO NOT confirm as this operation will cause you to lose your previous follow list.',
MuteListNotFoundConfirmation:
'Mute list not found. Do you want to create a new one? If you have muted users before, please DO NOT confirm as this operation will cause you to lose your previous mute list.'
}
}

View File

@@ -339,6 +339,10 @@ export default {
'No zaps yet': 'Sin zaps aún',
'No more reposts': 'No hay más reposts',
'No reposts yet': 'Sin reposts aún',
Reposts: 'Reposts'
Reposts: 'Reposts',
FollowListNotFoundConfirmation:
'Lista de seguidos no encontrada. ¿Quieres crear una nueva? Si has seguido usuarios antes, por favor NO confirmes ya que esta operación te hará perder tu lista de seguidos anterior.',
MuteListNotFoundConfirmation:
'Lista de silenciados no encontrada. ¿Quieres crear una nueva? Si has silenciado usuarios antes, por favor NO confirmes ya que esta operación te hará perder tu lista de silenciados anterior.'
}
}

View File

@@ -334,6 +334,10 @@ export default {
'No zaps yet': 'هنوز هیچ زپی وجود ندارد',
'No more reposts': 'هیچ بازنشر بیشتری وجود ندارد',
'No reposts yet': 'هنوز هیچ بازنشر وجود ندارد',
Reposts: 'بازنشرها'
Reposts: 'بازنشرها',
FollowListNotFoundConfirmation:
'فهرست دنبال‌کنندگان پیدا نشد. آیا می‌خواهید یکی جدید ایجاد کنید؟ اگر قبلاً کاربرانی را دنبال کرده‌اید، لطفاً تأیید نکنید زیرا این عملیات باعث از دست رفتن فهرست دنبال‌کنندگان قبلی شما خواهد شد.',
MuteListNotFoundConfirmation:
'فهرست بی‌صدا شده‌ها پیدا نشد. آیا می‌خواهید یکی جدید ایجاد کنید؟ اگر قبلاً کاربرانی را بی‌صدا کرده‌اید، لطفاً تأیید نکنید زیرا این عملیات باعث از دست رفتن فهرست بی‌صدا شده‌های قبلی شما خواهد شد.'
}
}

View File

@@ -339,6 +339,10 @@ export default {
'No zaps yet': 'Pas encore de zaps',
'No more reposts': 'Plus de reposts',
'No reposts yet': 'Pas encore de reposts',
Reposts: 'Reposts'
Reposts: 'Reposts',
FollowListNotFoundConfirmation:
'Liste de suivi non trouvée. Voulez-vous en créer une nouvelle ? Si vous avez suivi des utilisateurs auparavant, veuillez NE PAS confirmer car cette opération vous fera perdre votre liste de suivi précédente.',
MuteListNotFoundConfirmation:
'Liste de mise en sourdine non trouvée. Voulez-vous en créer une nouvelle ? Si vous avez mis en sourdine des utilisateurs auparavant, veuillez NE PAS confirmer car cette opération vous fera perdre votre liste de mise en sourdine précédente.'
}
}

View File

@@ -338,6 +338,10 @@ export default {
'No zaps yet': 'Ancora nessuno zap',
'No more reposts': 'Non ci sono più repost',
'No reposts yet': 'Ancora nessun repost',
Reposts: 'Repost'
Reposts: 'Repost',
FollowListNotFoundConfirmation:
'Elenco seguiti non trovato. Vuoi crearne uno nuovo? Se hai già seguito degli utenti in precedenza, per favore NON confermare poiché questa operazione causerà la perdita del tuo elenco seguiti precedente.',
MuteListNotFoundConfirmation:
'Elenco utenti silenziati non trovato. Vuoi crearne uno nuovo? Se hai già silenziato degli utenti in precedenza, per favore NON confermare poiché questa operazione causerà la perdita del tuo elenco utenti silenziati precedente.'
}
}

View File

@@ -336,6 +336,10 @@ export default {
'No zaps yet': 'まだZapはありません',
'No more reposts': 'これ以上のリポストはありません',
'No reposts yet': 'まだリポストはありません',
Reposts: 'リポスト'
Reposts: 'リポスト',
FollowListNotFoundConfirmation:
'フォローリストが見つかりません。新しいものを作成しますか?以前にユーザーをフォローしたことがある場合は、この操作により前のフォローリストが失われるため、確認しないでください。',
MuteListNotFoundConfirmation:
'ミュートリストが見つかりません。新しいものを作成しますか?以前にユーザーをミュートしたことがある場合は、この操作により前のミュートリストが失われるため、確認しないでください。'
}
}

View File

@@ -335,6 +335,10 @@ export default {
'No zaps yet': '아직 즙이 없습니다',
'No more reposts': '더 이상 리포스트가 없습니다',
'No reposts yet': '아직 리포스트가 없습니다',
Reposts: '리포스트'
Reposts: '리포스트',
FollowListNotFoundConfirmation:
'팔로우 목록을 찾을 수 없습니다. 새로 만드시겠습니까? 이전에 사용자를 팔로우한 적이 있다면 이 작업으로 인해 이전 팔로우 목록을 잃게 되므로 확인하지 마시기 바랍니다.',
MuteListNotFoundConfirmation:
'음소거 목록을 찾을 수 없습니다. 새로 만드시겠습니까? 이전에 사용자를 음소거한 적이 있다면 이 작업으로 인해 이전 음소거 목록을 잃게 되므로 확인하지 마시기 바랍니다.'
}
}

View File

@@ -338,6 +338,10 @@ export default {
'No zaps yet': 'Brak zapów',
'No more reposts': 'Brak kolejnych repostów',
'No reposts yet': 'Brak repostów',
Reposts: 'Reposty'
Reposts: 'Reposty',
FollowListNotFoundConfirmation:
'Lista obserwowanych nie została znaleziona. Czy chcesz utworzyć nową? Jeśli wcześniej obserwowałeś użytkowników, proszę NIE potwierdzaj, ponieważ ta operacja spowoduje utratę poprzedniej listy obserwowanych.',
MuteListNotFoundConfirmation:
'Lista wyciszonych nie została znaleziona. Czy chcesz utworzyć nową? Jeśli wcześniej wyciszałeś użytkowników, proszę NIE potwierdzaj, ponieważ ta operacja spowoduje utratę poprzedniej listy wyciszonych.'
}
}

View File

@@ -337,6 +337,10 @@ export default {
'No zaps yet': 'Ainda sem zaps',
'No more reposts': 'Sem mais reposts',
'No reposts yet': 'Ainda sem reposts',
Reposts: 'Reposts'
Reposts: 'Reposts',
FollowListNotFoundConfirmation:
'Lista de seguindo não encontrada. Deseja criar uma nova? Se você seguiu usuários antes, por favor NÃO confirme, pois esta operação fará você perder sua lista de seguindo anterior.',
MuteListNotFoundConfirmation:
'Lista de silenciados não encontrada. Deseja criar uma nova? Se você silenciou usuários antes, por favor NÃO confirme, pois esta operação fará você perder sua lista de silenciados anterior.'
}
}

View File

@@ -338,6 +338,10 @@ export default {
'No zaps yet': 'Ainda sem zaps',
'No more reposts': 'Sem mais reposts',
'No reposts yet': 'Ainda sem reposts',
Reposts: 'Reposts'
Reposts: 'Reposts',
FollowListNotFoundConfirmation:
'Lista de seguir não encontrada. Deseja criar uma nova? Se seguiu utilizadores anteriormente, por favor NÃO confirme, pois esta operação fará com que perca a sua lista de seguir anterior.',
MuteListNotFoundConfirmation:
'Lista de silenciados não encontrada. Deseja criar uma nova? Se silenciou utilizadores anteriormente, por favor NÃO confirme, pois esta operação fará com que perca a sua lista de silenciados anterior.'
}
}

View File

@@ -338,6 +338,10 @@ export default {
'No zaps yet': 'Пока нет запов',
'No more reposts': 'Больше нет репостов',
'No reposts yet': 'Пока нет репостов',
Reposts: 'Репосты'
Reposts: 'Репосты',
FollowListNotFoundConfirmation:
'Список подписок не найден. Хотите создать новый? Если вы уже подписывались на пользователей ранее, пожалуйста, НЕ подтверждайте, так как эта операция приведет к потере вашего предыдущего списка подписок.',
MuteListNotFoundConfirmation:
'Список заблокированных не найден. Хотите создать новый? Если вы уже блокировали пользователей ранее, пожалуйста, НЕ подтверждайте, так как эта операция приведет к потере вашего предыдущего списка заблокированных.'
}
}

View File

@@ -332,6 +332,10 @@ export default {
'No zaps yet': 'ยังไม่มีซาตส์',
'No more reposts': 'ไม่มีการรีโพสต์เพิ่มเติม',
'No reposts yet': 'ยังไม่มีการรีโพสต์',
Reposts: 'การรีโพสต์'
Reposts: 'การรีโพสต์',
FollowListNotFoundConfirmation:
'ไม่พบรายการติดตาม คุณต้องการสร้างรายการใหม่หรือไม่? หากคุณเคยติดตามผู้ใช้มาก่อน กรุณาอย่ายืนยัน เพราะการดำเนินการนี้จะทำให้คุณสูญเสียรายการติดตามก่อนหน้านี้',
MuteListNotFoundConfirmation:
'ไม่พบรายการปิดเสียง คุณต้องการสร้างรายการใหม่หรือไม่? หากคุณเคยปิดเสียงผู้ใช้มาก่อน กรุณาอย่ายืนยัน เพราะการดำเนินการนี้จะทำให้คุณสูญเสียรายการปิดเสียงก่อนหน้านี้'
}
}

View File

@@ -331,6 +331,10 @@ export default {
'No zaps yet': '暂无打闪',
'No more reposts': '没有更多转发了',
'No reposts yet': '暂无转发',
Reposts: '转发'
Reposts: '转发',
FollowListNotFoundConfirmation:
'未找到关注列表。你想创建一个新的吗?如果你之前已经关注了用户,请不要确认,因为此操作会导致你丢失之前的关注列表。',
MuteListNotFoundConfirmation:
'未找到屏蔽列表。你想创建一个新的吗?如果你之前已经屏蔽了用户,请不要确认,因为此操作会导致你丢失之前的屏蔽列表。'
}
}

View File

@@ -2,6 +2,7 @@ import { createFollowListDraftEvent } from '@/lib/draft-event'
import { getPubkeysFromPTags } from '@/lib/tag'
import client from '@/services/client.service'
import { createContext, useContext, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useNostr } from './NostrProvider'
type TFollowListContext = {
@@ -21,6 +22,7 @@ export const useFollowList = () => {
}
export function FollowListProvider({ children }: { children: React.ReactNode }) {
const { t } = useTranslation()
const { pubkey: accountPubkey, followListEvent, publish, updateFollowListEvent } = useNostr()
const followings = useMemo(
() => (followListEvent ? getPubkeysFromPTags(followListEvent.tags) : []),
@@ -31,6 +33,13 @@ export function FollowListProvider({ children }: { children: React.ReactNode })
if (!accountPubkey) return
const followListEvent = await client.fetchFollowListEvent(accountPubkey)
if (!followListEvent) {
const result = confirm(t('FollowListNotFoundConfirmation'))
if (!result) {
return
}
}
const newFollowListDraftEvent = createFollowListDraftEvent(
(followListEvent?.tags ?? []).concat([['p', pubkey]]),
followListEvent?.content

View File

@@ -5,10 +5,10 @@ import indexedDb from '@/services/indexed-db.service'
import dayjs from 'dayjs'
import { Event } from 'nostr-tools'
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { z } from 'zod'
import { useNostr } from './NostrProvider'
import { useTranslation } from 'react-i18next'
type TMuteListContext = {
mutePubkeys: string[]
@@ -116,12 +116,23 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
return event
}
const checkMuteListEvent = (muteListEvent: Event | null) => {
if (!muteListEvent) {
const result = confirm(t('MuteListNotFoundConfirmation'))
if (!result) {
throw new Error('Mute list not found')
}
}
}
const mutePubkeyPublicly = async (pubkey: string) => {
if (!accountPubkey || changing) return
setChanging(true)
try {
const muteListEvent = await client.fetchMuteListEvent(accountPubkey)
checkMuteListEvent(muteListEvent)
if (
muteListEvent &&
muteListEvent.tags.some(([tagName, tagValue]) => tagName === 'p' && tagValue === pubkey)
@@ -132,6 +143,8 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
const newMuteListEvent = await publishNewMuteListEvent(newTags, muteListEvent?.content)
const privateTags = await getPrivateTags(newMuteListEvent)
await updateMuteListEvent(newMuteListEvent, privateTags)
} catch (error) {
toast.error(t('Failed to mute user publicly') + ': ' + (error as Error).message)
} finally {
setChanging(false)
}
@@ -143,6 +156,7 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
setChanging(true)
try {
const muteListEvent = await client.fetchMuteListEvent(accountPubkey)
checkMuteListEvent(muteListEvent)
const privateTags = muteListEvent ? await getPrivateTags(muteListEvent) : []
if (privateTags.some(([tagName, tagValue]) => tagName === 'p' && tagValue === pubkey)) {
return
@@ -152,6 +166,8 @@ export function MuteListProvider({ children }: { children: React.ReactNode }) {
const cipherText = await nip04Encrypt(accountPubkey, JSON.stringify(newPrivateTags))
const newMuteListEvent = await publishNewMuteListEvent(muteListEvent?.tags ?? [], cipherText)
await updateMuteListEvent(newMuteListEvent, newPrivateTags)
} catch (error) {
toast.error(t('Failed to mute user privately') + ': ' + (error as Error).message)
} finally {
setChanging(false)
}