move community code to status-im2 (#18218)

This commit is contained in:
flexsurfer 2023-12-19 15:59:50 +01:00 committed by GitHub
parent 36c2f4706f
commit 842203a4d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 406 additions and 1240 deletions

View File

@ -1,32 +1,14 @@
(ns status-im.communities.core
(:require
[clojure.set :as set]
[clojure.string :as string]
[clojure.walk :as walk]
[quo.foundations.colors :as quo.colors]
[re-frame.core :as re-frame]
[status-im.bottom-sheet.events :as bottom-sheet]
[status-im.ui.components.colors :as colors]
[status-im.utils.deprecated-types :as types]
[status-im2.common.muting.helpers :refer [format-mute-till]]
[status-im2.common.toasts.events :as toasts]
[status-im2.common.universal-links :as universal-links]
[status-im2.constants :as constants]
[status-im2.contexts.chat.events :as chat.events]
status-im.communities.e2e
[status-im2.contexts.shell.activity-center.events :as activity-center]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def crop-size 1000)
(defn universal-link
[community-id]
(str (:external universal-links/domains)
"/c#"
community-id))
(defn <-request-to-join-community-rpc
[r]
(set/rename-keys r
@ -41,267 +23,14 @@
{}
requests))
(defn <-chats-rpc
[chats]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
(-> v
(assoc :can-post? (:canPost v))
(dissoc :canPost)
(update :members walk/stringify-keys))))
{}
chats))
(defn <-categories-rpc
[categ]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
v))
{}
categ))
(defn <-rpc
[c]
(-> c
(set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?
:adminSettings :admin-settings
:tokenPermissions :token-permissions
:communityTokensMetadata :tokens-metadata
:introMessage :intro-message
:muteTill :muted-till})
(update :admin-settings
set/rename-keys
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :token-permissions seq)
(update :categories <-categories-rpc)
(assoc :token-images
(reduce (fn [acc {sym :symbol image :image}]
(assoc acc sym image))
{}
(:communityTokensMetadata c)))))
(defn- fetch-community-id-input
[{:keys [db]}]
(:communities/community-id-input db))
(defn- handle-my-request
[db {:keys [community-id state deleted] :as request}]
(let [{:keys [name]} (get-in db [:communities community-id])]
(cond (and (= constants/community-request-to-join-state-pending state) (not deleted))
(assoc-in db [:communities/my-pending-requests-to-join community-id] request)
(and (= constants/community-request-to-join-state-accepted state) (not deleted))
(do (re-frame/dispatch [:toasts/upsert
{:icon :i/correct
:id :joined-community
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/joined-community {:community name})}])
(update-in db [:communities/my-pending-requests-to-join] dissoc community-id))
:else (update-in db [:communities/my-pending-requests-to-join] dissoc community-id))))
(defn handle-admin-request
[db {:keys [id community-id deleted] :as request}]
(if deleted
(update-in db [:communities/requests-to-join community-id] dissoc id)
(assoc-in db [:communities/requests-to-join community-id id] request)))
(rf/defn handle-requests-to-join
[{:keys [db]} requests]
(let [my-public-key (get-in db [:profile/profile :public-key])]
{:db (reduce (fn [db {:keys [public-key] :as request}]
(let [my-request? (= my-public-key public-key)]
(if my-request?
(handle-my-request db request)
(handle-admin-request db request))))
db
requests)}))
(rf/defn handle-removed-chats
[{:keys [db]} chat-ids]
{:db (reduce (fn [db chat-id]
(update db :chats dissoc chat-id))
db
chat-ids)})
(rf/defn handle-community
[{:keys [db]} {:keys [id] :as community}]
(when id
{:db (assoc-in db [:communities id] (<-rpc community))}))
(rf/defn handle-communities
{:events [::fetched]}
[{:keys [db]} communities]
{:db (reduce (fn [db {:keys [id] :as community}]
(assoc-in db [:communities id] (<-rpc community)))
db
communities)})
(rf/defn handle-my-pending-requests-to-join
{:events [:communities/fetched-my-communities-requests-to-join]}
[{:keys [db]} my-requests]
{:db (assoc db
:communities/my-pending-requests-to-join
(<-requests-to-join-community-rpc (types/js->clj my-requests)
:communityId))})
(rf/defn handle-response
[_ response-js]
{:dispatch [:sanitize-messages-and-process-response response-js]})
(rf/defn left
{:events [::left]}
[cofx response-js]
(let [community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/left-community {:community community-name})})
(navigation/navigate-back)
(activity-center/notifications-fetch-unread-count))))
(rf/defn joined
{:events [::joined ::requested-to-join]}
[cofx response-js]
(let [[event-name _] (:event cofx)
community-name (aget response-js "communities" 0 "name")]
(js/console.log "event-name")
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label (if (= event-name ::joined)
:t/joined-community
:t/requested-to-join-community)
{:community community-name})}))))
(rf/defn requested-to-join
{:events [:communities/requested-to-join]}
[cofx response-js]
(let [community-name (aget response-js "communities" 0 "name")]
(rf/merge cofx
(handle-response cofx response-js)
(navigation/hide-bottom-sheet)
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label
:t/requested-to-join-community
{:community community-name})}))))
(rf/defn cancelled-requested-to-join
{:events [:communities/cancelled-request-to-join]}
[cofx response-js]
(rf/merge cofx
(handle-response cofx response-js)
(toasts/upsert {:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label
:t/you-canceled-the-request)})))
(rf/defn export
{:events [::export-pressed]}
[_ community-id]
{:json-rpc/call [{:method "wakuext_exportCommunity"
:params [community-id]
:on-success #(re-frame/dispatch [:show-popover
{:view :export-community
:community-key %}])
:on-error #(do
(log/error "failed to export community" community-id %)
(re-frame/dispatch [::failed-to-export %]))}]})
(rf/defn import-community
{:events [::import]}
[cofx community-key]
{:json-rpc/call [{:method "wakuext_importCommunity"
:params [community-key]
:js-response true
:on-success #(re-frame/dispatch [::community-imported %])
:on-error #(do
(log/error "failed to import community" %)
(re-frame/dispatch [::failed-to-import %]))}]})
(rf/defn get-user-requests-to-join
{:events [:communities/get-user-requests-to-join]}
[_]
{:json-rpc/call [{:method "wakuext_myPendingRequestsToJoin"
:params []
:js-response true
:on-success #(re-frame/dispatch
[:communities/fetched-my-communities-requests-to-join %])
:on-error #(log/error "failed to get requests to join community")}]})
(rf/defn cancel-request-to-join
{:events [:communities/cancel-request-to-join]}
[_ request-to-join-id]
{:json-rpc/call [{:method "wakuext_cancelRequestToJoinCommunity"
:params [{:id request-to-join-id}]
:on-success #(re-frame/dispatch [:communities/cancelled-request-to-join %])
:js-response true
:on-error #(log/error "failed to cancel request to join community"
request-to-join-id
%)}]})
(rf/defn leave
{:events [:communities/leave]}
[{:keys [db]} community-id]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:effects/push-notifications-clear-message-notifications community-chat-ids
:dispatch [:shell/close-switcher-card community-id]
:json-rpc/call [{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(re-frame/dispatch [::left
%])
:on-error (fn [response]
(log/error
"failed to leave community"
community-id
response)
(re-frame/dispatch
[::failed-to-leave]))}]}))
(rf/defn status-tag-pressed
{:events [:communities/status-tag-pressed]}
[{:keys [db] :as cofx} community-id literal]
(let [{:keys [id]} (some #(when (= (:name %) literal) %)
(vals (get-in db [:communities community-id :chats])))]
(when (and id
(not= (:current-chat-id db) (str community-id id)))
(chat.events/navigate-to-chat cofx (str community-id id) nil))))
(rf/defn fetch
[_]
{:json-rpc/call [{:method "wakuext_communities"
:params []
:on-success #(re-frame/dispatch [::fetched %])
:on-error #(do
(log/error "failed to fetch communities" %)
(re-frame/dispatch [::failed-to-fetch %]))}]})
(rf/defn chat-created
{:events [::chat-created]}
[_ community-id user-pk]
{:json-rpc/call [{:method "wakuext_sendChatMessage"
:params [{:chatId user-pk
:text "Upgrade here to see an invitation to community"
:communityId community-id
:contentType constants/content-type-community}]
:js-response true
:on-success
#(re-frame/dispatch [:transport/message-sent %])
:on-error
#(log/error "failed to send a message" %)}]})
(rf/defn invite-users
{:events [::invite-people-confirmation-pressed]}
[cofx user-pk contacts]
@ -336,198 +65,17 @@
(log/error "failed to invite-user community" %)
(re-frame/dispatch [::failed-to-share-community %]))}]})))
(rf/defn create
{:events [::create-confirmation-pressed]}
[{:keys [db]}]
(let [{:keys [name description membership image]} (get db :communities/create)]
(let [params {:name name
:description description
:membership membership
:color (rand-nth colors/chat-colors)
:image (string/replace-first (str image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size}]
{:json-rpc/call [{:method "wakuext_createCommunity"
:params [params]
:js-response true
:on-success #(re-frame/dispatch [::community-created %])
:on-error #(do
(log/error "failed to create community" %)
(re-frame/dispatch [::failed-to-create-community %]))}]})))
(rf/defn edit
{:events [::edit-confirmation-pressed]}
[{:keys [db]}]
(let [{:keys [id name description membership new-image color]} (get db :communities/create)]
{:json-rpc/call [{:method "wakuext_editCommunity"
:params [{:communityID id
:name name
:description description
:color color
:image (string/replace-first (str new-image) #"file://" "")
:imageAx 0
:imageAy 0
:imageBx crop-size
:imageBy crop-size
:membership membership}]
:on-success #(re-frame/dispatch [::community-edited %])
:on-error #(do
(log/error "failed to edit community" %)
(re-frame/dispatch [::failed-to-edit-community %]))}]}))
(rf/defn create-channel
{:events [::create-channel-confirmation-pressed]}
[{:keys [db] :as cofx}]
(let [community-id (fetch-community-id-input cofx)
{:keys [name description color emoji]} (get db :communities/create-channel)]
{:json-rpc/call [{:method "wakuext_createCommunityChat"
:params [community-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:permissions {:access
constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-created %])
:on-error #(do
(log/error "failed to create community channel" %)
(re-frame/dispatch [::failed-to-create-community-channel %]))}]}))
(def community-chat-id-length 68)
(defn to-community-chat-id
[chat-id]
(subs chat-id community-chat-id-length))
(rf/defn edit-channel
{:events [::edit-channel-confirmation-pressed]}
[{:keys [db] :as cofx}]
(let [{:keys [name description color community-id emoji edit-channel-id category-id position]}
(get db :communities/create-channel)]
{:json-rpc/call [{:method "wakuext_editCommunityChat"
:params [community-id
edit-channel-id
{:identity {:display_name name
:description description
:color color
:emoji emoji}
:category_id category-id
:position position
:permissions {:access
constants/community-channel-access-no-membership}}]
:js-response true
:on-success #(re-frame/dispatch [::community-channel-edited %])
:on-error #(do
(log/error "failed to edit community channel" %)
(re-frame/dispatch [::failed-to-edit-community-channel %]))}]}))
(defn require-membership?
[permissions]
(not= constants/community-no-membership-access (:access permissions)))
(defn can-post?
[community _ local-chat-id]
(let [chat-id (to-community-chat-id local-chat-id)]
(get-in community [:chats chat-id :can-post?])))
(rf/defn reset-community-id-input
[{:keys [db]} id]
{:db (assoc db :communities/community-id-input id)})
(rf/defn reset-channel-info
[{:keys [db]}]
{:db (assoc db :communities/create-channel {})})
(re-frame/reg-event-fx :communities/invite-people-pressed
(fn [{:keys [db]} [id]]
{:db (assoc db :communities/community-id-input id)
:fx [[:dispatch [:hide-bottom-sheet]]
[:dispatch [:open-modal :invite-people-community {:invite? true}]]]}))
[:dispatch [:open-modal :legacy-invite-people-community {:invite? true}]]]}))
(re-frame/reg-event-fx :communities/share-community-pressed
(fn [{:keys [db]} [id]]
{:db (assoc db :communities/community-id-input id)
:fx [[:dispatch [:hide-bottom-sheet]]
[:dispatch [:open-modal :invite-people-community {}]]]}))
(rf/defn community-created
{:events [::community-created]}
[cofx response-js]
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn community-edited
{:events [::community-edited]}
[cofx response-js]
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn open-create-community
{:events [:legacy-only-for-e2e/open-create-community]}
[{:keys [db] :as cofx}]
(rf/merge cofx
{:db (assoc db :communities/create {:membership constants/community-no-membership-access})}
(navigation/navigate-to :community-create nil)))
(rf/defn create-closed-community
{:events [:fast-create-community/create-closed-community]}
[_]
{:json-rpc/call [{:method "wakuext_createClosedCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to create closed community." {:error %})}]
:dispatch [:hide-bottom-sheet]})
(rf/defn create-open-community
{:events [:fast-create-community/create-open-community]}
[_]
{:json-rpc/call [{:method "wakuext_createOpenCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to create open community." {:error %})}]
:dispatch [:hide-bottom-sheet]})
(rf/defn create-token-gated-community
{:events [:fast-create-community/create-token-gated-community]}
[_]
{:json-rpc/call [{:method "wakuext_createTokenGatedCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to create token gated community." {:error %})}]
:dispatch [:hide-bottom-sheet]})
(rf/defn open-edit-community
{:events [::open-edit-community :communities/open-edit-community]}
[{:keys [db] :as cofx} id]
(let [{:keys [name description images permissions color]} (get-in db [:communities id])
{:keys [access]} permissions]
(rf/merge cofx
{:db (assoc db
:communities/create
{:id id
:name name
:description description
:image (get-in images [:large :uri])
:membership access
:color color
:editing? true})}
(navigation/navigate-to :community-edit nil))))
(rf/defn community-imported
{:events [::community-imported]}
[cofx response-js]
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
[:dispatch [:open-modal :legacy-invite-people-community {}]]]}))
(rf/defn people-invited
{:events [::people-invited]}
@ -536,40 +84,6 @@
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn community-channel-created
{:events [::community-channel-created]}
[cofx response-js]
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn community-channel-edited
{:events [::community-channel-edited]}
[cofx response-js]
(rf/merge cofx
(navigation/navigate-back)
(handle-response response-js)))
(rf/defn create-field
{:events [::create-field]}
[{:keys [db]} field value]
{:db (assoc-in db [:communities/create field] value)})
(rf/defn remove-field
{:events [::remove-field]}
[{:keys [db]} field]
{:db (update-in db [:communities/create] dissoc field)})
(rf/defn create-channel-field
{:events [::create-channel-field]}
[{:keys [db]} field value]
{:db (assoc-in db [:communities/create-channel field] value)})
(rf/defn create-channel-fields
{:events [::create-channel-fields]}
[{:keys [db]} field-values]
{:db (update-in db [:communities/create-channel] merge field-values)})
(rf/defn member-banned
{:events [::member-banned]}
[cofx response-js]
@ -610,11 +124,6 @@
public-key
%)}]})
(rf/defn delete-community
{:events [::delete-community]}
[cofx community-id]
(log/error "Community delete is not yet implemented"))
(rf/defn requests-to-join-fetched
{:events [::requests-to-join-fetched]}
[{:keys [db]} community-id requests]
@ -623,149 +132,13 @@
(<-requests-to-join-community-rpc requests :id))})
(rf/defn fetch-requests-to-join
{:events [::fetch-requests-to-join]}
[cofx community-id]
{:events [:community/fetch-requests-to-join]}
[_ community-id]
{:json-rpc/call [{:method "wakuext_pendingRequestsToJoinForCommunity"
:params [community-id]
:on-success #(re-frame/dispatch [::requests-to-join-fetched community-id %])
:on-error #(log/error "failed to fetch requests-to-join" community-id %)}]})
(defn fetch-requests-to-join!
[community-id]
(re-frame/dispatch [::fetch-requests-to-join community-id]))
(rf/defn request-to-join-accepted
{:events [::request-to-join-accepted]}
[{:keys [db] :as cofx} community-id request-id response-js]
(rf/merge
cofx
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)
:dispatch-n [[:sanitize-messages-and-process-response response-js]
[:activity-center.notifications/mark-as-read request-id]]}))
(rf/defn request-to-join-declined
{:events [::request-to-join-declined]}
[{:keys [db] :as cofx} community-id request-id response-js]
(rf/merge
cofx
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)
:dispatch-n [[:sanitize-messages-and-process-response response-js]
[:activity-center.notifications/mark-as-read request-id]]}))
(rf/defn accept-request-to-join-pressed
{:events [:communities.ui/accept-request-to-join-pressed]}
[cofx community-id request-id]
{:json-rpc/call [{:method "wakuext_acceptRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(re-frame/dispatch [::request-to-join-accepted community-id request-id
%])
:on-error #(log/error "failed to accept requests-to-join"
community-id
request-id
%)}]})
(rf/defn decline-request-to-join-pressed
{:events [:communities.ui/decline-request-to-join-pressed]}
[cofx community-id request-id]
{:json-rpc/call [{:method "wakuext_declineRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(re-frame/dispatch [::request-to-join-declined community-id request-id
%])
:on-error #(log/error "failed to decline requests-to-join"
community-id
request-id)}]})
(rf/defn create-category
{:events [::create-category-confirmation-pressed]}
[_ community-id category-title chat-ids]
{:json-rpc/call [{:method "wakuext_createCommunityCategory"
:params [{:communityId community-id
:categoryName category-title
:chatIds (map #(string/replace % community-id "") chat-ids)}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to create community category" %)}]})
(rf/defn remove-chat-from-category
{:events [:remove-chat-from-community-category]}
[{:keys [db]} community-id id categoryID]
(let [category (get-in db [:communities community-id :categories categoryID])
category-chats (map :id
(filter #(and (= (:categoryID %) categoryID) (not= id (:id %)))
(vals (get-in db [:communities community-id :chats]))))]
{:json-rpc/call [{:method "wakuext_editCommunityCategory"
:params [{:communityId community-id
:categoryId categoryID
:categoryName (:name category)
:chatIds category-chats}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to remove chat from community" %)}]}))
(rf/defn delete-community-chat
{:events [:delete-community-chat]}
[_ community-id chat-id]
{:json-rpc/call [{:method "wakuext_deleteCommunityChat"
:params [community-id chat-id]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community chat" %)}]})
(rf/defn delete-category
{:events [:delete-community-category]}
[_ community-id category-id]
{:json-rpc/call [{:method "wakuext_deleteCommunityCategory"
:params [{:communityId community-id
:categoryId category-id}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to delete community category" %)}]})
(rf/defn change-category
{:events [::change-category-confirmation-pressed]}
[cofx community-id category-id {:keys [id position categoryID]}]
(if (not (string/blank? category-id))
{:json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId id
:position position}]
:js-response true
:on-success #(do
(re-frame/dispatch [:navigate-back])
(re-frame/dispatch [:sanitize-messages-and-process-response %]))
:on-error #(log/error "failed to change community category" %)}]}
(rf/merge cofx
(navigation/navigate-back)
(remove-chat-from-category community-id id categoryID))))
(rf/defn reorder-category-chat
{:events [::reorder-community-category-chat]}
[_ community-id category-id chat-id new-position]
{:json-rpc/call [{:method "wakuext_reorderCommunityChat"
:params [{:communityId community-id
:categoryId category-id
:chatId chat-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category chat" %)}]})
(rf/defn reorder-category
{:events [::reorder-community-category]}
[_ community-id category-id new-position]
{:json-rpc/call [{:method "wakuext_reorderCommunityCategories"
:params [{:communityId community-id
:categoryId category-id
:position new-position}]
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to reorder community category" %)}]})
(rf/defn member-role-updated
{:events [:community.member/role-updated]}
[cofx response-js]
@ -786,130 +159,3 @@
:community-id community-id
:public-key public-key
:role-id role-id})}]})
(rf/defn remove-role-from-member
{:events [:community.member/remove-role]}
[_ community-id public-key role-id]
{:json-rpc/call [{:method "wakuext_removeRoleFromMember"
:params [{:communityId community-id
:user public-key
:role role-id}]}
:on-success #(re-frame/dispatch [:community.member/role-updated %])
:on-error
#(log/error "failed to remove role from member"
{:error %
:community-id community-id
:public-key public-key
:role-id role-id})]})
(rf/defn fetched-collapsed-community-categories
{:events [:communities/fetched-collapsed-categories-success]}
[{:keys [db]} categories]
{:db (assoc db
:communities/collapsed-categories
(reduce
(fn [acc {:keys [communityId categoryId]}]
(assoc-in acc [communityId categoryId] true))
{}
categories))})
(rf/defn fetch-collapsed-community-categories
[_]
{:json-rpc/call [{:method "wakuext_collapsedCommunityCategories"
:params []
:on-success #(re-frame/dispatch
[:communities/fetched-collapsed-categories-success %])
:on-error #(log/error "failed to fetch collapsed community categories"
{:error :%})}]})
(rf/defn toggled-collapsed-category
{:events [:communities/toggled-collapsed-category-success]}
[{:keys [db]} community-id category-id collapsed?]
{:db (assoc-in db [:communities/collapsed-categories community-id category-id] collapsed?)})
(rf/defn toggle-collapsed-category
{:events [:communities/toggle-collapsed-category]}
[{:keys [db]} community-id category-id collapse?]
{:json-rpc/call [{:method "wakuext_toggleCollapsedCommunityCategory"
:params [{:communityId community-id
:categoryId category-id
:collapsed collapse?}]
:on-success #(re-frame/dispatch
[:communities/toggled-collapsed-category-success
community-id
category-id
collapse?])
:on-error #(log/error "failed to toggle collapse category"
{:error %
:community-id community-id
:event :communities/toggle-collapsed-category
:category-id category-id
:collapse? collapse?})}]})
(rf/defn check-and-delete-pending-request-to-join
{:events [:communities/check-and-delete-pending-request-to-join]}
[_]
{:json-rpc/call [{:method "wakuext_checkAndDeletePendingRequestToJoinCommunity"
:params []
:js-response true
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/info
"failed to fetch communities"
{:error %
:event
:communities/check-and-delete-pending-request-to-join-community})}]})
(rf/defn mute-community-chats
{:events [:community/mute-community-chats]}
[{:keys [db]} chat-id muted? muted-till]
(log/debug "muted community chat successfully" chat-id muted?)
{:db (update-in db [:chats chat-id] merge {:muted muted? :muted-till muted-till})})
(rf/defn mute-and-unmute-community-chats
{:events [:community/update-community-chats-mute-status]}
[{:keys [db]} community-id muted? mute-till]
(let [channels (get-in db [:communities community-id :chats])
chats (mapv vector (keys channels) (vals channels))]
(doseq [x chats]
(doseq [{:keys [id]} x]
(let [chat-id (str community-id id)]
(rf/dispatch [:community/mute-community-chats chat-id muted? mute-till]))))))
(rf/defn mute-chat-failed
{:events [:community/mute-community-failed]}
[{:keys [db]} community-id muted? error]
(log/error "mute community failed" community-id error)
{:db (update-in db [:communities community-id :muted] (not muted?))}
(rf/dispatch [:community/update-community-chats-mute-status community-id muted? error]))
(rf/defn mute-community-successfully
{:events [:community/mute-community-successful]}
[{:keys [db]} community-id muted? muted-till]
(log/debug "muted community successfully" community-id muted-till)
(rf/dispatch [:community/update-community-chats-mute-status community-id muted? muted-till])
(let [time-string (fn [mute-title mute-duration]
(i18n/label mute-title {:duration mute-duration}))]
{:db (assoc-in db [:communities community-id :muted-till] muted-till)
:dispatch [:toasts/upsert
{:icon :correct
:icon-color (quo.colors/theme-colors
quo.colors/success-60
quo.colors/success-50)
:text (if muted?
(when (some? muted-till)
(time-string :t/muted-until (format-mute-till muted-till)))
(i18n/label :t/community-unmuted))}]}))
(rf/defn set-community-muted
{:events [:community/set-muted]}
[{:keys [db]} community-id muted? muted-type]
(let [params (if muted? [{:communityId community-id :mutedType muted-type}] [community-id])
method (if muted? "wakuext_muteCommunityChats" "wakuext_unMuteCommunityChats")]
{:db (assoc-in db [:communities community-id :muted] muted?)
:json-rpc/call [{:method method
:params params
:on-error #(rf/dispatch [:community/mute-community-failed community-id
muted? %])
:on-success #(rf/dispatch [:community/mute-community-successful
community-id muted? %])}]}))

View File

@ -0,0 +1,35 @@
(ns status-im.communities.e2e
(:require [taoensso.timbre :as log]
[utils.re-frame :as rf]))
;;NOTE: ONLY FOR QA
(rf/defn create-closed-community
{:events [:fast-create-community/create-closed-community]}
[_]
{:json-rpc/call [{:method "wakuext_createClosedCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to create closed community." {:error %})}]
:dispatch [:hide-bottom-sheet]})
(rf/defn create-open-community
{:events [:fast-create-community/create-open-community]}
[_]
{:json-rpc/call [{:method "wakuext_createOpenCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to create open community." {:error %})}]
:dispatch [:hide-bottom-sheet]})
(rf/defn create-token-gated-community
{:events [:fast-create-community/create-token-gated-community]}
[_]
{:json-rpc/call [{:method "wakuext_createTokenGatedCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/error "failed to create token gated community." {:error %})}]
:dispatch [:hide-bottom-sheet]})

View File

@ -1,211 +0,0 @@
(ns status-im.ui.screens.communities.create
(:require
[clojure.string :as string]
[react-native.core :as rn]
[status-im.communities.core :as communities]
[status-im.ui.components.colors :as colors]
[status-im.ui.components.core :as quo]
[status-im.ui.components.icons.icons :as icons]
[status-im.ui.components.list.item :as list.item]
[status-im.ui.components.react :as react]
[status-im.ui.components.toolbar :as toolbar]
[status-im.utils.image :as utils.image]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def max-name-length 30)
(def max-description-length 140)
(defn valid?
[community-name community-description]
(and (not (string/blank? community-name))
(not (string/blank? community-description))
(<= (count community-name) max-name-length)
(<= (count community-description) max-description-length)))
(def crop-size 1000)
(def crop-opts
{:cropping true
:cropperCircleOverlay true
:width crop-size
:height crop-size})
(defn pick-pic
[]
;;we need timeout because first we need to close bottom sheet and then open picker
(js/setTimeout
(fn []
(react/show-image-picker
#(do (rf/dispatch [::communities/create-field :image (.-path ^js %)])
(rf/dispatch [::communities/create-field :new-image (.-path ^js %)]))
crop-opts))
300))
(defn take-pic
[]
;;we need timeout because first we need to close bottom sheet and then open picker
(js/setTimeout
(fn []
(react/show-image-picker-camera
#(do (rf/dispatch [::communities/create-field :image (.-path ^js %)])
(rf/dispatch [::communities/create-field :new-image (.-path ^js %)]))
crop-opts))
300))
(defn bottom-sheet
[has-picture editing?]
(fn []
[:<>
[list.item/list-item
{:accessibility-label :take-photo
:theme :accent
:icon :main-icons/camera
:title (i18n/label :t/community-image-take)
:on-press #(do
(rf/dispatch [:bottom-sheet/hide-old])
(take-pic))}]
[list.item/list-item
{:accessibility-label :pick-photo
:icon :main-icons/gallery
:theme :accent
:title (i18n/label :t/community-image-pick)
:on-press #(do
(rf/dispatch [:bottom-sheet/hide-old])
(pick-pic))}]
(when (and has-picture (not editing?))
[list.item/list-item
{:accessibility-label :remove-photo
:icon :main-icons/delete
:theme :accent
:title (i18n/label :t/community-image-remove)
:on-press #(do
(rf/dispatch [:bottom-sheet/hide-old])
(rf/dispatch [::communities/remove-field :image]))}])]))
(defn photo-picker
[]
(let [{:keys [image editing?]} (rf/sub [:communities/create])]
[rn/view
{:style {:padding-top 16
:align-items :center}}
[rn/touchable-opacity
{:on-press (fn []
(rn/dismiss-keyboard!)
(rf/dispatch [:bottom-sheet/show-sheet-old
{:content (bottom-sheet (boolean image) editing?)}]))}
[rn/view
{:style {:width 128
:height 128}}
[rn/view
{:style {:flex 1
:border-radius 64
:background-color (colors/get-color :ui-01)
:justify-content :center
:align-items :center}}
(if image
[rn/image
{:source (utils.image/source image)
:style {:width 128
:height 128
:border-radius 64}
:resize-mode :cover
:accessibility-label :community-image}]
[:<>
[icons/icon :main-icons/photo {:color (colors/get-color :icon-02)}]
[quo/text {:color :secondary}
(i18n/label :t/community-thumbnail-upload)]])]
[rn/view
{:style {:position :absolute
:top 0
:right 7}}
[rn/view
{:style {:width 40
:height 40
:background-color (colors/get-color :interactive-01)
:border-radius 20
:align-items :center
:justify-content :center
:shadow-offset {:width 0 :height 1}
:shadow-radius 6
:shadow-opacity 1
:shadow-color (colors/get-color :shadow-01)
:elevation 2}}
[icons/icon :main-icons/add {:color colors/white}]]]]]]))
(defn countable-label
[{:keys [label text max-length]}]
[rn/view
{:style {:padding-bottom 10
:justify-content :space-between
:align-items :flex-end
:flex-direction :row
:flex-wrap :nowrap}}
[quo/text label]
[quo/text
{:size :small
:color (if (> (count text) max-length)
:negative
:secondary)}
(str (count text) "/" max-length)]])
(defn form
[]
(let [{:keys [name description editing?]} (rf/sub [:communities/create])]
[rn/scroll-view
{:keyboard-should-persist-taps :handled
:style {:flex 1}
:content-container-style {:padding-vertical 16}}
[rn/view
{:style {:padding-bottom 16
:padding-top 10
:padding-horizontal 16}}
[countable-label
{:label (i18n/label :t/name-your-community)
:text name
:max-length max-name-length}]
[quo/text-input
{:placeholder (i18n/label :t/name-your-community-placeholder)
:default-value name
:on-change-text #(rf/dispatch [::communities/create-field :name %])
:auto-focus true}]]
[rn/view
{:style {:padding-bottom 16
:padding-top 10
:padding-horizontal 16}}
[countable-label
{:label (i18n/label :t/give-a-short-description-community)
:text description
:max-length max-description-length}]
[quo/text-input
{:placeholder (i18n/label :t/give-a-short-description-community)
:multiline true
:default-value description
:on-change-text #(rf/dispatch [::communities/create-field :description %])}]]
[quo/list-header {:color :main}
(i18n/label :t/community-thumbnail-image)]
[photo-picker]
(when-not editing?
[:<>
[quo/separator {:style {:margin-vertical 10}}]
[list.item/list-item
{:title (i18n/label :t/membership-button)
:accessory :text
:on-press #(rf/dispatch [:navigate-to :community-membership])
:chevron true
:size :small}]])]))
(defn view
[]
(let [{:keys [name description]} (rf/sub [:communities/create])]
[rn/keyboard-avoiding-view {:style {:flex 1}}
[form]
[toolbar/toolbar
{:show-border? true
:center
[quo/button
{:disabled (not (valid? name description))
:type :secondary
:on-press #(debounce/dispatch-and-chill [::communities/create-confirmation-pressed] 3000)}
(i18n/label :t/create)]}]]))

View File

@ -1,35 +0,0 @@
(ns status-im.ui.screens.communities.import
(:require
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im.communities.core :as communities]
[status-im.ui.components.core :as quo]
[status-im.ui.components.toolbar :as toolbar]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [community-key (reagent/atom "")]
(fn []
[:<>
[rn/scroll-view
{:style {:flex 1}
:content-container-style {:padding 16}}
[rn/view
{:style {:padding-bottom 16
:padding-top 10}}
[quo/text-input
{:label (i18n/label :t/community-key)
:placeholder (i18n/label :t/community-key-placeholder)
:on-change-text #(reset! community-key %)
:default-value @community-key
:auto-focus true}]]]
[toolbar/toolbar
{:show-border? true
:center [quo/button
{:disabled (= @community-key "")
:type :secondary
:on-press #(rf/dispatch [::communities/import @community-key])}
(i18n/label :t/import)]}]])))

View File

@ -43,7 +43,7 @@
(swap! selected disj public-key)
(swap! selected conj public-key)))}]))
(defn invite
(defn legacy-invite
[]
(let [user-pk (reagent/atom "")
contacts-selected (reagent/atom #{})

View File

@ -138,11 +138,12 @@
:key-fn identity
:render-fn render-member}]]))))
(defn members-container
(defn legacy-members-container
[]
(reagent/create-class
{:display-name "community-members-view"
:component-did-mount (fn []
(communities/fetch-requests-to-join! (get (rf/sub [:get-screen-params])
:community-id)))
(rf/dispatch [:community/fetch-requests-to-join
(get (rf/sub [:get-screen-params])
:community-id)]))
:reagent-render members}))

View File

@ -1,49 +0,0 @@
(ns status-im.ui.screens.communities.membership
(:require
[react-native.core :as rn]
[status-im.communities.core :as communities]
[status-im.ui.components.core :as quo]
[status-im.ui.components.list.item :as list.item]
[status-im.ui.components.toolbar :as toolbar]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(def options
{constants/community-on-request-access
{:title :t/membership-approval
:description :t/membership-approval-description}
constants/community-no-membership-access
{:title :t/membership-free
:description :t/membership-free-description}})
(defn option
[{:keys [title description]} {:keys [selected on-select]}]
[:<>
[list.item/list-item
{:title (i18n/label title)
:size :small
:accessory :radio
:active selected
:on-press on-select}]
[quo/list-footer
(i18n/label description)]
[quo/separator {:style {:margin-vertical 8}}]])
(defn membership-view
[]
(let [{:keys [membership]} (rf/sub [:communities/create])]
[:<>
[rn/scroll-view {}
(doall
(for [[id o] options]
^{:key (str "option-" id)}
[option o
{:selected (= id membership)
:on-select #(rf/dispatch [::communities/create-field :membership id])}]))]
[toolbar/toolbar
{:show-border? true
:center [quo/button
{:type :secondary
:on-press #(rf/dispatch [:navigate-back])}
(i18n/label :t/done)]}]]))

View File

@ -27,18 +27,6 @@
:subtitle secondary-name
:icon [chat-icon/contact-icon-contacts-tab row]}]))
(defn- on-toggle-default
[allow-new-users? checked? public-key]
(cond
checked?
(re-frame/dispatch [:deselect-contact public-key allow-new-users?])
;; Only allow new users if not reached the maximum
(and (not checked?)
allow-new-users?)
(re-frame/dispatch [:select-contact public-key allow-new-users?])))
(defn- on-toggle-participant
[allow-new-users? checked? public-key]
(cond
@ -64,10 +52,6 @@
:active contact-selected?
:accessory :checkbox}])))
(defn- group-toggle-contact
[contact _ _ allow-new-users?]
[toggle-item allow-new-users? :is-contact-selected? contact on-toggle-default])
(defn- group-toggle-participant
[contact _ _ allow-new-users?]
[toggle-item allow-new-users? :is-participant-selected? contact on-toggle-participant])
@ -179,37 +163,6 @@
:render-fn toggle-fn}]
[no-contacts-view {:no-contacts no-contacts-label}])]])))
;; Start group chat
(views/defview contact-toggle-list
[]
(views/letsubs [contacts [:contacts/active]
selected-contacts-count [:selected-contacts-count]]
[react/keyboard-avoiding-view
{:style styles/group-container
:ignore-offset true}
[topbar/topbar
{:use-insets false
:border-bottom false
:title (i18n/label :t/new-group-chat)
:subtitle (i18n/label :t/group-chat-members-count
{:selected (inc selected-contacts-count)
:max constants/max-group-chat-participants})}]
[searchable-contact-list
{:contacts contacts
:no-contacts-label (i18n/label :t/group-chat-no-contacts)
:toggle-fn group-toggle-contact
:allow-new-users? (< selected-contacts-count
(dec constants/max-group-chat-participants))}]
[toolbar/toolbar
{:show-border? true
:right
[quo/button
{:type :secondary
:after :main-icon/next
:accessibility-label :next-button
:on-press #(re-frame/dispatch [:navigate-to :new-group])}
(i18n/label :t/next)]}]]))
;; Add participants to existing group chat
(views/defview add-participants-toggle-list
[]
@ -241,38 +194,3 @@
:disabled (zero? selected-contacts-count)
:on-press #(re-frame/dispatch [:group-chats.ui/add-members-pressed])}
(i18n/label :t/add)]}]])))
(views/defview edit-group-chat-name
[]
(views/letsubs [{:keys [name chat-id]} [:chats/current-chat]
new-group-chat-name (reagent/atom nil)]
[kb-presentation/keyboard-avoiding-view {:style styles/group-container}
[react/scroll-view
{:style {:padding 16
:flex 1}}
[quo/text-input
{:on-change-text #(reset! new-group-chat-name %)
:default-value name
:on-submit-editing #(when (seq @new-group-chat-name)
(re-frame/dispatch [:group-chats.ui/name-changed chat-id
@new-group-chat-name]))
:placeholder (i18n/label :t/enter-contact-code)
:accessibility-label :new-chat-name
:return-key-type :go}]]
[react/view {:style {:flex 1}}]
[toolbar/toolbar
{:show-border? true
:center
[quo/button
{:type :secondary
:accessibility-label :done
:disabled (and (<= (count @new-group-chat-name) 1)
(not (nil? @new-group-chat-name)))
:on-press #(cond
(< 1 (count @new-group-chat-name))
(re-frame/dispatch [:group-chats.ui/name-changed chat-id
@new-group-chat-name])
(nil? @new-group-chat-name)
(re-frame/dispatch [:navigate-back]))}
(i18n/label :t/done)]}]]))

View File

@ -10,11 +10,8 @@
[status-im.ui.screens.bootnodes-settings.views :as bootnodes-settings]
[status-im.ui.screens.browser.bookmarks.views :as bookmarks]
[status-im.ui.screens.bug-report :as bug-report]
[status-im.ui.screens.communities.create :as communities.create]
[status-im.ui.screens.communities.import :as communities.import]
[status-im.ui.screens.communities.invite :as communities.invite]
[status-im.ui.screens.communities.members :as members]
[status-im.ui.screens.communities.membership :as membership]
[status-im.ui.screens.contacts-list.views :as contacts-list]
[status-im.ui.screens.currency-settings.views :as currency-settings]
[status-im.ui.screens.dapps-permissions.views :as dapps-permissions]
@ -89,7 +86,6 @@
:component progress/progress}
;;CHAT
{:name :group-chat-profile
;;TODO animated-header
:options {:insets {:top? true}}
@ -98,6 +94,10 @@
;;TODO parameter in the event
:options {:insets {:top? true}}
:component profile.group-chat/group-chat-invite}
{:name :legacy-community-members
;;TODO custom subtitle
:options {:insets {:top? true}}
:component members/legacy-members-container}
{:name :stickers
:options {:insets {:top? true}
@ -108,35 +108,10 @@
:options {:insets {:top? true}}
:component stickers/pack}
;; Community (legacy only for e2e needed)
{:name :community-members
;;TODO custom subtitle
:options {:insets {:top? true}}
:component members/members-container}
{:name :contact-toggle-list
;;TODO custom subtitle
:options {:insets {:top? true}}
:component group-chat/contact-toggle-list}
{:name :new-group
:options {:insets {:top? true}}
;;TODO custom subtitle
:component group-chat/new-group}
{:name :community-import
:options {:topBar {:title {:text (i18n/label :t/import-community-title)}}
:insets {:top? true
:bottom? true}}
:component communities.import/view}
{:name :community-create
:options {:topBar {:title {:text (i18n/label :t/new-community-title)}}
:insets {:top? true
:bottom? true}}
:component communities.create/view}
{:name :community-membership
:options {:topBar {:title {:text (i18n/label :t/membership-title)}}
:insets {:top? true
:bottom? true}}
:component membership/membership-view}
;;WALLET
@ -430,11 +405,11 @@
:component group-chat/add-participants-toggle-list}
;[Communities] Invite people
{:name :invite-people-community
{:name :legacy-invite-people-community
;;TODO dyn title
:options {:insets {:bottom? true
:top? true}}
:component communities.invite/invite}
:component communities.invite/legacy-invite}
;[Wallet] Recipient
{:name :recipient

View File

@ -11,7 +11,8 @@
[rn/view {:flex 1}
[quo/text style/title-column-text
label]]
[plus-button/plus-button
{:on-press handler
:accessibility-label accessibility-label
:customization-color customization-color}]])
(when handler
[plus-button/plus-button
{:on-press handler
:accessibility-label accessibility-label
:customization-color customization-color}])])

View File

@ -433,3 +433,12 @@
{:events [:chat/check-last-chat]}
[{:keys [db]}]
{:effects.chat/open-last-chat (get-in db [:profile/profile :key-uid])})
(rf/defn status-tag-pressed
{:events [:communities/status-tag-pressed]}
[{:keys [db] :as cofx} community-id literal]
(let [{:keys [id]} (some #(when (= (:name %) literal) %)
(vals (get-in db [:communities community-id :chats])))]
(when (and id
(not= (:current-chat-id db) (str community-id id)))
(navigate-to-chat cofx (str community-id id) nil))))

View File

@ -1,7 +1,7 @@
(ns status-im2.contexts.chat.messages.link-preview.events
(:require
[camel-snake-kebab.core :as csk]
[status-im.communities.core :as models.communities]
[status-im2.contexts.communities.events :as communities]
[status-im2.contexts.profile.settings.events :as profile.settings.events]
[taoensso.timbre :as log]
[utils.collection]
@ -50,7 +50,7 @@
(some? community)
(assoc :dispatch
[:chat.ui/cache-link-preview-data (community-link community-id) community]))
(models.communities/handle-community community)))
(communities/handle-community community)))
(rf/defn handle-community-failed-to-resolve
{:events [:chat.ui/community-failed-to-resolve]}

View File

@ -4,7 +4,6 @@
[clojure.string :as string]
[status-im.browser.core :as browser]
[status-im.chat.models.message :as models.message]
[status-im.communities.core :as models.communities]
[status-im.data-store.activities :as data-store.activities]
[status-im.data-store.chats :as data-store.chats]
[status-im.data-store.invitations :as data-store.invitations]
@ -18,6 +17,7 @@
[status-im2.contexts.chat.events :as chat.events]
[status-im2.contexts.chat.messages.content.reactions.events :as reactions]
[status-im2.contexts.chat.messages.pin.events :as messages.pin]
[status-im2.contexts.communities.events :as communities]
[status-im2.contexts.contacts.events :as models.contact]
[status-im2.contexts.shell.activity-center.events :as activity-center]
[taoensso.timbre :as log]
@ -101,7 +101,7 @@
(js-delete response-js "communities")
(rf/merge cofx
(process-next response-js sync-handler)
(models.communities/handle-communities communities-clj)))
(communities/handle-communities communities-clj)))
(seq bookmarks)
(let [bookmarks-clj (types/js->clj bookmarks)]
@ -122,16 +122,16 @@
(js-delete response-js "removedChats")
(rf/merge cofx
(process-next response-js sync-handler)
(models.communities/handle-removed-chats removed-chats-clj)))
(communities/handle-removed-chats removed-chats-clj)))
(seq requests-to-join-community)
(let [requests (->> requests-to-join-community
types/js->clj
(map models.communities/<-request-to-join-community-rpc))]
(map communities/<-request-to-join-community-rpc))]
(js-delete response-js "requestsToJoinCommunity")
(rf/merge cofx
(process-next response-js sync-handler)
(models.communities/handle-requests-to-join requests)))
(communities/handle-requests-to-join requests)))
(seq emoji-reactions)
(let [reactions (types/js->clj emoji-reactions)]

View File

@ -0,0 +1,47 @@
(ns status-im2.contexts.communities.actions.community-options.events
(:require [quo.foundations.colors :as quo.colors]
[status-im2.common.muting.helpers :as muting.helpers]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :community/update-community-chats-mute-status
(fn [{:keys [db]} [community-id muted? muted-till]]
{:db
(reduce
#(update-in %1 [:chats (str community-id %2)] assoc :muted muted? :muted-till muted-till)
db
(keys (get-in db [:communities community-id :chats])))}))
(rf/reg-event-fx :community/mute-community-failed
(fn [{:keys [db]} [community-id muted? error]]
(log/error "mute community failed" community-id error)
{:db (assoc-in db [:communities community-id :muted] (not muted?))
:dispatch [:community/update-community-chats-mute-status community-id muted? error]}))
(rf/reg-event-fx :community/mute-community-successful
(fn [{:keys [db]} [community-id muted? muted-till]]
(let [time-string (fn [mute-title mute-duration]
(i18n/label mute-title {:duration mute-duration}))]
{:db (assoc-in db [:communities community-id :muted-till] muted-till)
:dispatch-n [[:community/update-community-chats-mute-status community-id muted? muted-till]
[:toasts/upsert
{:icon :correct
:icon-color (quo.colors/theme-colors quo.colors/success-60 quo.colors/success-50)
:text (if muted?
(when (some? muted-till)
(time-string :t/muted-until
(muting.helpers/format-mute-till muted-till)))
(i18n/label :t/community-unmuted))}]]})))
(rf/reg-event-fx :community/set-muted
(fn [{:keys [db]} [community-id muted? muted-type]]
(let [params (if muted? [{:communityId community-id :mutedType muted-type}] [community-id])
method (if muted? "wakuext_muteCommunityChats" "wakuext_unMuteCommunityChats")]
{:db (assoc-in db [:communities community-id :muted] muted?)
:json-rpc/call [{:method method
:params params
:on-error #(rf/dispatch [:community/mute-community-failed community-id
muted? %])
:on-success #(rf/dispatch [:community/mute-community-successful
community-id muted? %])}]})))

View File

@ -20,7 +20,7 @@
{:icon :i/members
:accessibility-label :view-members
:label (i18n/label :t/view-members)
:on-press #(hide-sheet-and-dispatch [:navigate-to :community-members
:on-press #(hide-sheet-and-dispatch [:navigate-to :legacy-community-members
{:community-id id}])})
(defn view-rules

View File

@ -1,31 +1,21 @@
(ns status-im2.contexts.communities.actions.home-plus.view
(:require
[quo.core :as quo]
[status-im2.config :as config]
[utils.re-frame :as rf]))
(defn view
[]
[quo/action-drawer
[(concat [{:icon :i/download
:accessibility-label :import-community
:label "Import community"
:on-press #(rf/dispatch [:navigate-to :community-import])}]
(when config/fast-create-community-enabled?
[{:icon :i/communities
:accessibility-label :create-community
:label "Create community (only for e2e)"
:on-press #(rf/dispatch [:legacy-only-for-e2e/open-create-community])}
{:icon :i/communities
:accessibility-label :create-closed-community
:label "Create closed community"
:on-press #(rf/dispatch [:fast-create-community/create-closed-community])}
{:icon :i/communities
:accessibility-label :create-open-community
:label "Create open community"
:on-press #(rf/dispatch [:fast-create-community/create-open-community])}
{:icon :i/communities
:accessibility-label :create-token-gated-community
:label "Create token-gated community"
:on-press #(rf/dispatch
[:fast-create-community/create-token-gated-community])}]))]])
[[{:icon :i/communities
:accessibility-label :create-closed-community
:label "Create closed community (only for testing)"
:on-press #(rf/dispatch [:fast-create-community/create-closed-community])}
{:icon :i/communities
:accessibility-label :create-open-community
:label "Create open community (only for testing)"
:on-press #(rf/dispatch [:fast-create-community/create-open-community])}
{:icon :i/communities
:accessibility-label :create-token-gated-community
:label "Create token-gated community (only for testing)"
:on-press #(rf/dispatch
[:fast-create-community/create-token-gated-community])}]]])

View File

@ -0,0 +1,48 @@
(ns status-im2.contexts.communities.actions.leave.events
(:require [status-im.ui.components.colors :as colors]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :communities/cancel-request-to-join-success
(fn [_ [response-js]]
{:fx [[:dispatch [:sanitize-messages-and-process-response response-js]]
[:dispatch
[:toasts/upsert
{:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/you-canceled-the-request)}]]]}))
(rf/reg-event-fx :communities/cancel-request-to-join
(fn [_ [request-to-join-id]]
{:json-rpc/call
[{:method "wakuext_cancelRequestToJoinCommunity"
:params [{:id request-to-join-id}]
:on-success #(rf/dispatch [:communities/cancel-request-to-join-success %])
:js-response true
:on-error #(log/error "failed to cancel request to join community" request-to-join-id %)}]}))
(rf/reg-event-fx :communities/left
(fn [_ [response-js]]
(let [community-name (aget response-js "communities" 0 "name")]
{:fx [[:dispatch [:sanitize-messages-and-process-response response-js]]
[:dispatch
[:toasts/upsert
{:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/left-community {:community community-name})}]]
[:dispatch [:activity-center.notifications/fetch-unread-count]]
[:dispatch [:navigate-back]]]})))
(rf/reg-event-fx :communities/leave
(fn [{:keys [db]} [community-id]]
(let [community-chat-ids (map #(str community-id %)
(keys (get-in db [:communities community-id :chats])))]
{:effects/push-notifications-clear-message-notifications community-chat-ids
:dispatch [:shell/close-switcher-card community-id]
:json-rpc/call
[{:method "wakuext_leaveCommunity"
:params [community-id]
:js-response true
:on-success #(rf/dispatch [:communities/left %])
:on-error #(log/error "failed to leave community" community-id %)}]})))

View File

@ -0,0 +1,179 @@
(ns status-im2.contexts.communities.events
(:require [clojure.set :as set]
[clojure.walk :as walk]
[status-im.ui.components.colors :as colors]
[status-im2.constants :as constants]
status-im2.contexts.communities.actions.community-options.events
status-im2.contexts.communities.actions.leave.events
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn <-request-to-join-community-rpc
[r]
(set/rename-keys r
{:communityId :community-id
:publicKey :public-key
:chatId :chat-id}))
(defn <-requests-to-join-community-rpc
[requests key-fn]
(reduce #(assoc %1 (key-fn %2) (<-request-to-join-community-rpc %2)) {} requests))
(defn <-chats-rpc
[chats]
(reduce-kv (fn [acc k v]
(assoc acc
(name k)
(-> v
(assoc :can-post? (:canPost v))
(dissoc :canPost)
(update :members walk/stringify-keys))))
{}
chats))
(defn <-categories-rpc
[categ]
(reduce-kv #(assoc %1 (name %2) %3) {} categ))
(defn <-rpc
[c]
(-> c
(set/rename-keys {:canRequestAccess :can-request-access?
:canManageUsers :can-manage-users?
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
:canJoin :can-join?
:requestedToJoinAt :requested-to-join-at
:isMember :is-member?
:adminSettings :admin-settings
:tokenPermissions :token-permissions
:communityTokensMetadata :tokens-metadata
:introMessage :intro-message
:muteTill :muted-till})
(update :admin-settings
set/rename-keys
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
(update :members walk/stringify-keys)
(update :chats <-chats-rpc)
(update :token-permissions seq)
(update :categories <-categories-rpc)
(assoc :token-images
(reduce (fn [acc {sym :symbol image :image}]
(assoc acc sym image))
{}
(:communityTokensMetadata c)))))
(rf/defn handle-community
[{:keys [db]} {:keys [id] :as community}]
(when id
{:db (assoc-in db [:communities id] (<-rpc community))}))
(rf/defn handle-removed-chats
[{:keys [db]} chat-ids]
{:db (reduce (fn [db chat-id]
(update db :chats dissoc chat-id))
db
chat-ids)})
(defn- handle-my-request
[db {:keys [community-id state deleted] :as request}]
(let [{:keys [name]} (get-in db [:communities community-id])]
(cond (and (= constants/community-request-to-join-state-pending state) (not deleted))
(assoc-in db [:communities/my-pending-requests-to-join community-id] request)
(and (= constants/community-request-to-join-state-accepted state) (not deleted))
(do (rf/dispatch [:toasts/upsert
{:icon :i/correct
:id :joined-community
:icon-color (:positive-01 @colors/theme)
:text (i18n/label :t/joined-community {:community name})}])
(update-in db [:communities/my-pending-requests-to-join] dissoc community-id))
:else (update-in db [:communities/my-pending-requests-to-join] dissoc community-id))))
(defn handle-admin-request
[db {:keys [id community-id deleted] :as request}]
(if deleted
(update-in db [:communities/requests-to-join community-id] dissoc id)
(assoc-in db [:communities/requests-to-join community-id id] request)))
(rf/defn handle-requests-to-join
[{:keys [db]} requests]
(let [my-public-key (get-in db [:profile/profile :public-key])]
{:db (reduce (fn [db {:keys [public-key] :as request}]
(let [my-request? (= my-public-key public-key)]
(if my-request?
(handle-my-request db request)
(handle-admin-request db request))))
db
requests)}))
(rf/defn handle-communities
{:events [:community/fetch-success]}
[{:keys [db]} communities]
{:db (reduce (fn [db {:keys [id] :as community}]
(assoc-in db [:communities id] (<-rpc community)))
db
communities)})
(rf/reg-event-fx :communities/request-to-join-result
(fn [{:keys [db]} [community-id request-id response-js]]
{:db (update-in db [:communities/requests-to-join community-id] dissoc request-id)
:dispatch-n [[:sanitize-messages-and-process-response response-js]
[:activity-center.notifications/mark-as-read request-id]]}))
(rf/reg-event-fx :communities/decline-request-to-join-pressed
(fn [_ [community-id request-id]]
{:json-rpc/call
[{:method "wakuext_declineRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(rf/dispatch [:communities/request-to-join-result community-id request-id %])
:on-error #(log/error "failed to decline " community-id request-id)}]}))
(rf/reg-event-fx :communities/accept-request-to-join-pressed
(fn [_ [community-id request-id]]
{:json-rpc/call
[{:method "wakuext_acceptRequestToJoinCommunity"
:params [{:id request-id}]
:js-response true
:on-success #(rf/dispatch [:communities/request-to-join-result community-id request-id %])
:on-error #(log/error "failed to accept requests-to-join" community-id request-id %)}]}))
(rf/reg-event-fx :communities/get-user-requests-to-join-success
(fn [{:keys [db]} [requests]]
{:db (assoc db
:communities/my-pending-requests-to-join
(<-requests-to-join-community-rpc requests :communityId))}))
(rf/reg-event-fx :communities/get-user-requests-to-join
(fn [_]
{:json-rpc/call [{:method "wakuext_myPendingRequestsToJoin"
:params []
:on-success #(rf/dispatch [:communities/get-user-requests-to-join-success %])
:on-error #(log/error "failed to get requests to join community")}]}))
(rf/reg-event-fx :communities/fetched-collapsed-categories-success
(fn [{:keys [db]} [categories]]
{:db (assoc db
:communities/collapsed-categories
(reduce
(fn [acc {:keys [communityId categoryId]}]
(assoc-in acc [communityId categoryId] true))
{}
categories))}))
(rf/reg-event-fx :community/fetch
(fn [_]
{:json-rpc/call [{:method "wakuext_communities"
:params []
:on-success #(rf/dispatch [:community/fetch-success %])
:on-error #(log/error "failed to fetch communities" %)}
{:method "wakuext_checkAndDeletePendingRequestToJoinCommunity"
:params []
:js-response true
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
:on-error #(log/info "failed to fetch communities" %)}
{:method "wakuext_collapsedCommunityCategories"
:params []
:on-success #(rf/dispatch [:communities/fetched-collapsed-categories-success %])
:on-error #(log/error "failed to fetch collapsed community categories" %)}]}))

View File

@ -9,6 +9,7 @@
[status-im2.common.home.empty-state.view :as common.empty-state]
[status-im2.common.home.header-spacing.view :as common.header-spacing]
[status-im2.common.resources :as resources]
[status-im2.config :as config]
[status-im2.contexts.communities.actions.community-options.view :as options]
[status-im2.contexts.communities.actions.home-plus.view :as actions.home-plus]
[status-im2.contexts.shell.jump-to.constants :as jump-to.constants]
@ -62,7 +63,8 @@
(def ^:private banner-data
{:title-props
{:label (i18n/label :t/communities)
:handler #(rf/dispatch [:show-bottom-sheet {:content actions.home-plus/view}])
:handler (when config/fast-create-community-enabled?
#(rf/dispatch [:show-bottom-sheet {:content actions.home-plus/view}]))
:accessibility-label :new-communities-button}
:card-props
{:on-press #(rf/dispatch [:navigate-to :discover-communities])

View File

@ -1,7 +1,9 @@
(ns status-im2.contexts.communities.overview.events
(:require
[status-im.data-store.communities :as data-store]
[status-im.ui.components.colors :as colors]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(rf/reg-event-fx :communities/check-all-community-channels-permissions-success
@ -76,6 +78,19 @@
:event :communities/requested-to-join-error})
{:db (assoc-in db [:password-authentication :error] error)}))
(rf/reg-event-fx :communities/requested-to-join
(fn [_ [response-js]]
(let [community-name (aget response-js "communities" 0 "name")]
{:fx [[:dispatch [:sanitize-messages-and-process-response response-js]]
[:dispatch [:hide-bottom-sheet]]
[:dispatch
[:toasts/upsert
{:icon :correct
:icon-color (:positive-01 @colors/theme)
:text (i18n/label
:t/requested-to-join-community
{:community community-name})}]]]})))
(defn request-to-join-with-signatures
[_ [community-id addresses-to-reveal signatures]]
{:fx [[:json-rpc/call
@ -92,3 +107,23 @@
:on-error [:communities/requested-to-join-error community-id]}]]]})
(rf/reg-event-fx :communities/request-to-join-with-signatures request-to-join-with-signatures)
(rf/reg-event-fx :communities/toggled-collapsed-category-success
(fn [{:keys [db]} [community-id category-id collapsed?]]
{:db (assoc-in db [:communities/collapsed-categories community-id category-id] collapsed?)}))
(rf/reg-event-fx :communities/toggle-collapsed-category
(fn [_ [community-id category-id collapse?]]
{:json-rpc/call
[{:method "wakuext_toggleCollapsedCommunityCategory"
:params [{:communityId community-id
:categoryId category-id
:collapsed collapse?}]
:on-success #(rf/dispatch
[:communities/toggled-collapsed-category-success community-id category-id collapse?])
:on-error #(log/error "failed to toggle collapse category"
{:error %
:community-id community-id
:event :communities/toggle-collapsed-category
:category-id category-id
:collapse? collapse?})}]}))

View File

@ -3,7 +3,6 @@
[native-module.core :as native-module]
[re-frame.core :as re-frame]
[status-im.browser.core :as browser]
[status-im.communities.core :as communities]
[status-im.data-store.chats :as data-store.chats]
[status-im.data-store.settings :as data-store.settings]
[status-im.data-store.switcher-cards :as switcher-cards-store]
@ -93,7 +92,8 @@
:profile/profile (merge profile-overview settings))
(assoc-in [:wallet :ui :tokens-loading?] true))
:fx [[:dispatch [:wallet/get-ethereum-chains]]
[:dispatch [:universal-links/generate-profile-url]]]}
[:dispatch [:universal-links/generate-profile-url]]
[:dispatch [:community/fetch]]]}
(notifications/load-preferences)
(data-store.chats/fetch-chats-preview
{:on-success
@ -101,9 +101,6 @@
(rf/dispatch [:communities/get-user-requests-to-join])
(re-frame/dispatch [:profile.login/get-chats-callback]))})
(profile.config/get-node-config)
(communities/fetch)
(communities/fetch-collapsed-community-categories)
(communities/check-and-delete-pending-request-to-join)
(logging/set-log-level (:log-level settings))
(activity-center/notifications-fetch-pending-contact-requests)
(activity-center/update-seen-state)

View File

@ -41,9 +41,9 @@
(= membership-status constants/activity-center-membership-status-pending)
[common/swipeable
{:left-button swipe-button-accept
:left-on-press #(rf/dispatch [:communities.ui/accept-request-to-join-pressed community-id id])
:left-on-press #(rf/dispatch [:communities/accept-request-to-join-pressed community-id id])
:right-button swipe-button-decline
:right-on-press #(rf/dispatch [:communities.ui/decline-request-to-join-pressed community-id
:right-on-press #(rf/dispatch [:communities/decline-request-to-join-pressed community-id
id])
:active-swipeable active-swipeable
:extra-fn extra-fn}
@ -98,7 +98,7 @@
:accessibility-label :decline-join-request
:on-press (fn []
(rf/dispatch
[:communities.ui/decline-request-to-join-pressed
[:communities/decline-request-to-join-pressed
community-id id]))}
{:type :button
:subtype :positive
@ -107,7 +107,7 @@
:accessibility-label :accept-join-request
:on-press (fn []
(rf/dispatch
[:communities.ui/accept-request-to-join-pressed
[:communities/accept-request-to-join-pressed
community-id id]))}]
nil)}]]))

View File

@ -14,6 +14,7 @@
status-im2.contexts.chat.composer.events
status-im2.contexts.chat.events
status-im2.contexts.chat.photo-selector.events
status-im2.contexts.communities.events
status-im2.contexts.communities.overview.events
status-im2.contexts.emoji-picker.events
status-im2.contexts.onboarding.common.overlay.events

View File

@ -1,22 +0,0 @@
(ns status-im2.integration-test.community-test
(:require [cljs.test :refer [deftest]]
[day8.re-frame.test :as rf-test]
[re-frame.core :as rf]
[status-im.multiaccounts.logout.core :as logout]
[status-im2.integration-test.constants :as constants]
[test-helpers.integration :as h]))
(deftest create-community-test
(h/log-headline :create-community-test)
(rf-test/run-test-async
(h/with-app-initialized
(h/with-account
(rf/dispatch-sync [:legacy-only-for-e2e/open-create-community])
(doseq [[k v] (dissoc constants/community :membership)]
(rf/dispatch-sync [:status-im.communities.core/create-field k v]))
(rf/dispatch [:status-im.communities.core/create-confirmation-pressed])
(rf-test/wait-for
[:status-im.communities.core/community-created]
(h/assert-community-created)
(h/logout)
(rf-test/wait-for [::logout/logout-method]))))))

View File

@ -2,7 +2,6 @@
(:require
[clojure.string :as string]
[re-frame.core :as re-frame]
[status-im.communities.core :as communities]
[status-im.group-chats.core :as group-chat]
[status-im.group-chats.db :as group-chats.db]
[status-im2.constants :as constants]
@ -216,7 +215,7 @@
:member? true)
(and (chat.events/community-chat? current-chat)
(communities/can-post? community my-public-key (:chat-id current-chat)))
(get-in community [:chats (subs (:chat-id current-chat) 68) :can-post?]))
(assoc :able-to-send-message? true)
(not group-chat)