<commit_before>(ns chat.client.store
  (:require [cljs-utils.core :refer [flip]]))

(defonce app-state
  (atom {:open-group-id nil
         :threads {}
         :users {}
         :tags {}
         :groups {}
         :page {:type :inbox}
         :session nil
         :error-msg nil
         :invitations []
         :notifications {:window-visible? true
                         :unread-count 0}
         :user {:open-thread-ids #{}
                :subscribed-tag-ids #{}
                :user-id nil
                :nickname nil}}))

(defn- key-by-id [coll]
  (reduce (fn [memo x]
            (assoc memo (x :id) x)) {} coll))

(defn- transact! [ks f]
  (swap! app-state update-in ks f))

; window visibility & notifications

(defn set-window-visibility!
  [visible?]
  (when visible?
    (transact! [:notifications :unread-count] (constantly 0))
    (set! (.-title js/document) "Chat"))
  (transact! [:notifications :window-visible?] (constantly visible?)))

; error

(defn display-error! [msg]
  (transact! [:error-msg] (constantly msg)))

(defn clear-error! []
  (transact! [:error-msg] (constantly nil)))

; page

(defn set-group-and-page! [group-id page-id]
  (swap! app-state (fn [s] (assoc s
                             :open-group-id group-id
                             :page page-id
                             ))))
; session

(defn set-session! [session]
  (transact! [:session] (constantly session)))

(defn clear-session! []
  (transact! [:session] (constantly nil)))

(defn set-nickname! [nick]
  (transact! [:session :nickname] (constantly nick)))

; users

(defn add-users! [users]
  (transact! [:users] #(merge % (key-by-id users))))

(defn add-user! [user]
  (transact! [:users] #(assoc % (:id user) user)))

(defn update-user-nick! [user-id nick]
  (transact! [:users user-id :nickname] (constantly nick)))

(defn update-user-status! [user-id status]
  (transact! [:users user-id :status] (constantly status)))

(defn all-users []
  (vals (get-in @app-state [:users])))

(defn users-in-group [group-id]
  (filter (fn [u] (contains? (set (u :group-ids)) group-id)) (vals (@app-state :users))))

(defn users-in-open-group []
  (users-in-group (@app-state :open-group-id)))

(defn user-in-open-group? [user-id]
  (contains? (set (get-in @app-state [:users user-id :group-ids])) (@app-state :open-group-id)))

(defn nickname->user [nickname]
  (->> (get-in @app-state [:users])
       vals
       (filter (fn [u] (= nickname (u :nickname))))
       ; nicknames are unique, so take the first
       first))

(defn valid-user-id? [user-id]
  (some? (get-in @app-state [:users user-id])))

; threads and messages

(defn update-thread-last-open-at [thread-id]
  (transact! [:threads thread-id :last-open-at] (constantly js/Date.)))

(defn set-open-threads! [threads]
  (transact! [:threads] (constantly (key-by-id threads)))
  (transact! [:user :open-thread-ids] (constantly (set (map :id threads)))))

(defn- maybe-create-thread! [thread-id]
  (when-not (get-in @app-state [:threads thread-id])
    (transact! [:threads thread-id] (constantly {:id thread-id
                                                 :messages []
                                                 :tag-ids #{}
                                                 :mentioned-ids #{}} )))
  (transact! [:user :open-thread-ids] #(conj % thread-id)))

(defn add-message! [message]
  (maybe-create-thread! (message :thread-id))
  (transact! [:threads (message :thread-id) :messages] #(conj % message))
  (update-thread-last-open-at (message :thread-id))
  (transact! [:threads (message :thread-id) :tag-ids] #(apply conj (set %) (message :mentioned-tag-ids)))
  (transact! [:threads (message :thread-id) :mentioned-ids] #(apply conj (set %) (message :mentioned-user-ids))))

(defn add-open-thread! [thread]
  ; TODO move notifications logic out of here
  (when-not (get-in @app-state [:notifications :window-visible?])
    (transact! [:notifications :unread-count] inc)
    (set! (.-title js/document)
          (str "Chat (" (get-in @app-state [:notifications :unread-count]) ")")))

  (transact! [:threads (thread :id)] (constantly thread))
  (transact! [:user :open-thread-ids] #(conj % (thread :id))))

(defn hide-thread! [thread-id]
  (transact! [:threads] #(dissoc % thread-id))
  (transact! [:user :open-thread-ids] #(disj % thread-id)))

(defn id->thread [thread-id]
  (get-in @app-state [:threads thread-id]))

(defn open-thread? [thread-id]
  (contains? (set (get-in @app-state [:user :open-thread-ids])) thread-id))
<commit_msg>don't remove thread from app-state when hiding<commit_after>(ns chat.client.store
  (:require [cljs-utils.core :refer [flip]]))

(defonce app-state
  (atom {:open-group-id nil
         :threads {}
         :users {}
         :tags {}
         :groups {}
         :page {:type :inbox}
         :session nil
         :error-msg nil
         :invitations []
         :notifications {:window-visible? true
                         :unread-count 0}
         :user {:open-thread-ids #{}
                :subscribed-tag-ids #{}
                :user-id nil
                :nickname nil}}))

(defn- key-by-id [coll]
  (reduce (fn [memo x]
            (assoc memo (x :id) x)) {} coll))

(defn- transact! [ks f]
  (swap! app-state update-in ks f))

; window visibility & notifications

(defn set-window-visibility!
  [visible?]
  (when visible?
    (transact! [:notifications :unread-count] (constantly 0))
    (set! (.-title js/document) "Chat"))
  (transact! [:notifications :window-visible?] (constantly visible?)))

; error

(defn display-error! [msg]
  (transact! [:error-msg] (constantly msg)))

(defn clear-error! []
  (transact! [:error-msg] (constantly nil)))

; page

(defn set-group-and-page! [group-id page-id]
  (swap! app-state (fn [s] (assoc s
                             :open-group-id group-id
                             :page page-id
                             ))))
; session

(defn set-session! [session]
  (transact! [:session] (constantly session)))

(defn clear-session! []
  (transact! [:session] (constantly nil)))

(defn set-nickname! [nick]
  (transact! [:session :nickname] (constantly nick)))

; users

(defn add-users! [users]
  (transact! [:users] #(merge % (key-by-id users))))

(defn add-user! [user]
  (transact! [:users] #(assoc % (:id user) user)))

(defn update-user-nick! [user-id nick]
  (transact! [:users user-id :nickname] (constantly nick)))

(defn update-user-status! [user-id status]
  (transact! [:users user-id :status] (constantly status)))

(defn all-users []
  (vals (get-in @app-state [:users])))

(defn users-in-group [group-id]
  (filter (fn [u] (contains? (set (u :group-ids)) group-id)) (vals (@app-state :users))))

(defn users-in-open-group []
  (users-in-group (@app-state :open-group-id)))

(defn user-in-open-group? [user-id]
  (contains? (set (get-in @app-state [:users user-id :group-ids])) (@app-state :open-group-id)))

(defn nickname->user [nickname]
  (->> (get-in @app-state [:users])
       vals
       (filter (fn [u] (= nickname (u :nickname))))
       ; nicknames are unique, so take the first
       first))

(defn valid-user-id? [user-id]
  (some? (get-in @app-state [:users user-id])))

; threads and messages

(defn update-thread-last-open-at [thread-id]
  (transact! [:threads thread-id :last-open-at] (constantly js/Date.)))

(defn set-open-threads! [threads]
  (transact! [:threads] (constantly (key-by-id threads)))
  (transact! [:user :open-thread-ids] (constantly (set (map :id threads)))))

(defn- maybe-create-thread! [thread-id]
  (when-not (get-in @app-state [:threads thread-id])
    (transact! [:threads thread-id] (constantly {:id thread-id
                                                 :messages []
                                                 :tag-ids #{}
                                                 :mentioned-ids #{}} )))
  (transact! [:user :open-thread-ids] #(conj % thread-id)))

(defn add-message! [message]
  (maybe-create-thread! (message :thread-id))
  (transact! [:threads (message :thread-id) :messages] #(conj % message))
  (update-thread-last-open-at (message :thread-id))
  (transact! [:threads (message :thread-id) :tag-ids] #(apply conj (set %) (message :mentioned-tag-ids)))
  (transact! [:threads (message :thread-id) :mentioned-ids] #(apply conj (set %) (message :mentioned-user-ids))))

(defn add-open-thread! [thread]
  ; TODO move notifications logic out of here
  (when-not (get-in @app-state [:notifications :window-visible?])
    (transact! [:notifications :unread-count] inc)
    (set! (.-title js/document)
          (str "Chat (" (get-in @app-state [:notifications :unread-count]) ")")))

  (transact! [:threads (thread :id)] (constantly thread))
  (transact! [:user :open-thread-ids] #(conj % (thread :id))))

(defn hide-thread! [thread-id]
  (transact! [:user :open-thread-ids] #(disj % thread-id)))

(defn id->thread [thread-id]
  (get-in @app-state [:threads thread-id]))

(defn open-thread? [thread-id]
  (contains? (set (get-in @app-state [:user :open-thread-ids])) thread-id))

{'fraction_non_alphanumeric': 0.18478742249778565, 'fraction_numerical': 0.0004428697962798937, 'mean_word_length': 2.801767676767677, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5739533', 'n_tokens_mistral': 3217, 'n_tokens_neox': 3160, 'n_words': 780}