tangled
alpha
login
or
join now
margin.at
/
margin
87
fork
atom
Write on the margins of the internet. Powered by the AT Protocol.
margin.at
extension
web
atproto
comments
87
fork
atom
overview
issues
4
pulls
1
pipelines
fix profile page
scanash.com
1 month ago
9870ecb9
d76abc06
+63
-37
2 changed files
expand all
collapse all
unified
split
backend
internal
db
tags.go
web
src
pages
Profile.jsx
+36
-11
backend/internal/db/tags.go
···
1
package db
2
3
-
import "fmt"
4
-
5
type TrendingTag struct {
6
Tag string `json:"tag"`
7
Count int `json:"count"`
8
}
9
10
func (db *DB) GetTrendingTags(limit int) ([]TrendingTag, error) {
11
-
query := `
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
12
SELECT
13
json_each.value as tag,
14
COUNT(*) as count
···
16
WHERE tags_json IS NOT NULL
17
AND tags_json != ''
18
AND tags_json != '[]'
19
-
AND created_at > %s
20
GROUP BY tag
21
HAVING count > 2
22
ORDER BY count DESC
23
LIMIT ?
24
`
25
-
26
-
dateFilter := "datetime('now', '-7 days')"
27
-
if db.driver == "postgres" {
28
-
dateFilter = "NOW() - INTERVAL '7 days'"
29
-
}
30
-
31
-
rows, err := db.Query(db.Rebind(fmt.Sprintf(query, dateFilter)), limit)
32
if err != nil {
33
return nil, err
34
}
···
1
package db
2
0
0
3
type TrendingTag struct {
4
Tag string `json:"tag"`
5
Count int `json:"count"`
6
}
7
8
func (db *DB) GetTrendingTags(limit int) ([]TrendingTag, error) {
9
+
var query string
10
+
if db.driver == "postgres" {
11
+
query = `
12
+
SELECT
13
+
value as tag,
14
+
COUNT(*) as count
15
+
FROM annotations, json_array_elements_text(tags_json::json) as value
16
+
WHERE tags_json IS NOT NULL
17
+
AND tags_json != ''
18
+
AND tags_json != '[]'
19
+
AND created_at > NOW() - INTERVAL '7 days'
20
+
GROUP BY tag
21
+
HAVING count > 2
22
+
ORDER BY count DESC
23
+
LIMIT ?
24
+
`
25
+
rows, err := db.Query(db.Rebind(query), limit)
26
+
if err != nil {
27
+
return nil, err
28
+
}
29
+
defer rows.Close()
30
+
31
+
var tags []TrendingTag
32
+
for rows.Next() {
33
+
var t TrendingTag
34
+
if err := rows.Scan(&t.Tag, &t.Count); err != nil {
35
+
return nil, err
36
+
}
37
+
tags = append(tags, t)
38
+
}
39
+
return tags, nil
40
+
}
41
+
42
+
query = `
43
SELECT
44
json_each.value as tag,
45
COUNT(*) as count
···
47
WHERE tags_json IS NOT NULL
48
AND tags_json != ''
49
AND tags_json != '[]'
50
+
AND created_at > datetime('now', '-7 days')
51
GROUP BY tag
52
HAVING count > 2
53
ORDER BY count DESC
54
LIMIT ?
55
`
56
+
rows, err := db.Query(db.Rebind(query), limit)
0
0
0
0
0
0
57
if err != nil {
58
return nil, err
59
}
+27
-26
web/src/pages/Profile.jsx
···
81
const handle = routeHandle || user?.did || user?.handle;
82
const isOwnProfile = user && (user.did === handle || user.handle === handle);
83
84
-
if (authLoading) {
85
-
return (
86
-
<div className="profile-page">
87
-
<div className="feed">
88
-
{[1, 2, 3].map((i) => (
89
-
<div key={i} className="card">
90
-
<div
91
-
className="skeleton skeleton-text"
92
-
style={{ width: "40%" }}
93
-
/>
94
-
<div className="skeleton skeleton-text" />
95
-
<div
96
-
className="skeleton skeleton-text"
97
-
style={{ width: "60%" }}
98
-
/>
99
-
</div>
100
-
))}
101
-
</div>
102
-
</div>
103
-
);
104
-
}
105
-
106
-
if (!handle) {
107
-
return <Navigate to="/login" replace />;
108
-
}
109
-
110
useEffect(() => {
0
111
async function fetchProfile() {
112
try {
113
setLoading(true);
···
202
alert("Failed to delete key: " + err.message);
203
}
204
};
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
205
206
const displayName = profile?.displayName || profile?.handle || handle;
207
const displayHandle =
···
81
const handle = routeHandle || user?.did || user?.handle;
82
const isOwnProfile = user && (user.did === handle || user.handle === handle);
83
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
84
useEffect(() => {
85
+
if (!handle) return;
86
async function fetchProfile() {
87
try {
88
setLoading(true);
···
177
alert("Failed to delete key: " + err.message);
178
}
179
};
180
+
181
+
if (authLoading) {
182
+
return (
183
+
<div className="profile-page">
184
+
<div className="feed">
185
+
{[1, 2, 3].map((i) => (
186
+
<div key={i} className="card">
187
+
<div
188
+
className="skeleton skeleton-text"
189
+
style={{ width: "40%" }}
190
+
/>
191
+
<div className="skeleton skeleton-text" />
192
+
<div
193
+
className="skeleton skeleton-text"
194
+
style={{ width: "60%" }}
195
+
/>
196
+
</div>
197
+
))}
198
+
</div>
199
+
</div>
200
+
);
201
+
}
202
+
203
+
if (!handle) {
204
+
return <Navigate to="/login" replace />;
205
+
}
206
207
const displayName = profile?.displayName || profile?.handle || handle;
208
const displayHandle =