Skip to content

Commit 029fd7f

Browse files
committed
implement achievements
1 parent b55ef76 commit 029fd7f

File tree

12 files changed

+166
-44
lines changed

12 files changed

+166
-44
lines changed

MyApp.ServiceInterface/App/CreateAnswerCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ await db.InsertAsync(new Achievement
9898
Score = 1,
9999
CreatedDate = DateTime.UtcNow,
100100
});
101+
appConfig.IncrUnreadAchievementsFor(answer.CreatedBy);
101102
}
102103
}
103104
}

MyApp.ServiceInterface/App/CreatePostCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ await db.InsertAsync(new Achievement
8888
Score = 1,
8989
CreatedDate = DateTime.UtcNow,
9090
});
91+
appConfig.IncrUnreadAchievementsFor(post.CreatedBy!);
9192
}
9293
}
9394
}

MyApp.ServiceInterface/App/CreatePostVotesCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ await db.InsertAsync(new Achievement
4444
Score = vote.Score > 0 ? 10 : -1, // 10 points for UpVote, -1 point for DownVote
4545
CreatedDate = DateTime.UtcNow,
4646
});
47+
appConfig.IncrUnreadAchievementsFor(vote.RefUserName!);
4748
}
4849
}
4950

MyApp.ServiceInterface/App/MarkAsReadCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public async Task ExecuteAsync(MarkAsRead request)
2222
appConfig.UsersUnreadNotifications[userName] = (int) await db.CountAsync(
2323
db.From<Notification>().Where(x => x.UserName == userName && !x.Read));
2424
}
25+
// Mark all achievements as read isn't used, they're auto reset after viewed
2526
if (request.AllAchievements == true)
2627
{
2728
await db.UpdateOnlyAsync(() => new Achievement { Read = true }, x => x.UserName == userName);

MyApp.ServiceInterface/UserServices.cs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public object Any(CreateAvatar request)
138138
public async Task<object> Any(GetLatestNotifications request)
139139
{
140140
var userName = Request.GetClaimsPrincipal().GetUserName();
141-
var notificationPosts = await Db.SelectMultiAsync<Notification,Post>(Db.From<Notification>()
141+
var tuples = await Db.SelectMultiAsync<Notification,Post>(Db.From<Notification>()
142142
.Join<Post>()
143143
.Where(x => x.UserName == userName)
144144
.OrderByDescending(x => x.Id)
@@ -151,23 +151,53 @@ Notification Merge(Notification notification, Post post)
151151
return notification;
152152
}
153153

154-
var results = notificationPosts.Map(x => Merge(x.Item1, x.Item2));
154+
var results = tuples.Map(x => Merge(x.Item1, x.Item2));
155155

156156
return new GetLatestNotificationsResponse
157157
{
158158
Results = results
159159
};
160160
}
161+
162+
public class SumAchievement
163+
{
164+
public int PostId { get; set; }
165+
public string RefId { get; set; }
166+
public int Score { get; set; }
167+
public DateTime CreatedDate { get; set; }
168+
public string Title { get; set; }
169+
public string Slug { get; set; }
170+
}
161171

162172
public async Task<object> Any(GetLatestAchievements request)
163173
{
164174
var userName = Request.GetClaimsPrincipal().GetUserName();
175+
176+
var sumAchievements = await Db.SelectAsync<SumAchievement>(
177+
@"SELECT A.PostId, A.RefId, Sum(A.Score) AS Score, Max(A.CreatedDate) AS CreatedDate, P.Title, p.Slug
178+
FROM Achievement A LEFT JOIN Post P on (A.PostId = P.Id)
179+
WHERE UserName = @userName
180+
GROUP BY A.PostId, A.RefId
181+
LIMIT 30", new { userName });
182+
183+
var i = 0;
184+
var results = sumAchievements.Map(x => new Achievement
185+
{
186+
Id = ++i,
187+
PostId = x.PostId,
188+
RefId = x.RefId,
189+
Title = x.Title.SubstringWithEllipsis(0,100),
190+
Score = x.Score,
191+
CreatedDate = x.CreatedDate,
192+
Href = $"/questions/{x.PostId}/{x.Slug}",
193+
});
194+
195+
// Reset everytime they view the latest achievements
196+
appConfig.UsersUnreadAchievements[userName!] = 0;
197+
165198
return new GetLatestAchievementsResponse
166199
{
167-
Results = await Db.SelectAsync(Db.From<Achievement>()
168-
.Where(x => x.UserName == userName)
169-
.OrderByDescending(x => x.Id)
170-
.Take(30))
200+
Results = results
171201
};
172202
}
173203

MyApp/Components/Account/Pages/Register.razor

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@
8484

8585
public async Task RegisterUser(EditContext editContext)
8686
{
87+
if (char.IsDigit(Input.UserName[0]))
88+
{
89+
identityErrors = [new() { Code = "InvalidUserName", Description = "Username can't start with a digit" }];
90+
return;
91+
}
92+
8793
var user = CreateUser();
8894
user.LastLoginIp = HttpContext.GetRemoteIp();
8995
user.LastLoginDate = DateTime.UtcNow;

MyApp/Components/Shared/Header.razor

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,15 @@
6161
</li>
6262
<li class="relative flex flex-wrap just-fu-start m-0">
6363
<div onclick="toggleNotifications(this)" class="select-none group relative hover:bg-gray-100 dark:hover:bg-gray-800 p-4 cursor-pointer">
64-
<svg class="w-6 h-6 text-gray-400 group-hover:text-gray-500 dark:group-hover:text-sky-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
65-
<path fill="currentColor" d="M5 21q-.825 0-1.412-.587T3 19V5q0-.825.588-1.412T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.587 1.413T19 21zm0-2h14v-3h-3q-.75.95-1.787 1.475T12 18q-1.175 0-2.212-.525T8 16H5zm7-3q.95 0 1.725-.55T14.8 14H19V5H5v9h4.2q.3.9 1.075 1.45T12 16m-7 3h14z"/>
66-
</svg>
67-
<svg class=@CssUtils.ClassNames("absolute right-1 top-1 h-4 w-4", AppConfig.HasUnreadNotifications(HttpContext?.User.GetUserName()) ? "text-red-500" : "text-transparent") viewBox="0 0 32 32"><circle cx="16" cy="16" r="8" fill="currentColor"/></svg>
64+
<svg class="w-6 h-6 text-gray-400 group-hover:text-gray-500 dark:group-hover:text-sky-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M5 21q-.825 0-1.412-.587T3 19V5q0-.825.588-1.412T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.587 1.413T19 21zm0-2h14v-3h-3q-.75.95-1.787 1.475T12 18q-1.175 0-2.212-.525T8 16H5zm7-3q.95 0 1.725-.55T14.8 14H19V5H5v9h4.2q.3.9 1.075 1.45T12 16m-7 3h14z"/></svg>
65+
<svg id="new-notifications" class=@CssUtils.ClassNames("absolute right-1 top-1 h-4 w-4", AppConfig.HasUnreadNotifications(HttpContext?.User.GetUserName()) ? "text-red-500" : "text-transparent") viewBox="0 0 32 32"><circle cx="16" cy="16" r="8" fill="currentColor"/></svg>
6866
</div>
6967
<div id="notifications-menu"></div>
7068
</li>
71-
<li onclick="toggleAchievements(this)" class="mr-2 relative flex flex-wrap just-fu-start m-0">
72-
<div class="group relative hover:bg-gray-100 dark:hover:bg-gray-800 p-4 cursor-pointer">
69+
<li class="mr-2 relative flex flex-wrap just-fu-start m-0">
70+
<div onclick="toggleAchievements(this)" class="select-none group relative hover:bg-gray-100 dark:hover:bg-gray-800 p-4 cursor-pointer">
7371
<svg class="w-6 h-6 cursor-pointer text-gray-400 group-hover:text-gray-500 dark:group-hover:text-sky-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M8 3h8v8h6v10H2V9h6zm2 16h4V5h-4zm6 0h4v-6h-4zm-8 0v-8H4v8z"/></svg>
74-
<svg class=@CssUtils.ClassNames("absolute right-1 top-1 h-4 w-4", AppConfig.HasUnreadAchievements(HttpContext?.User.GetUserName()) ? "text-red-500" : "text-transparent") viewBox="0 0 32 32"><circle cx="16" cy="16" r="8" fill="currentColor"/></svg>
72+
<svg id="new-achievements" class=@CssUtils.ClassNames("absolute right-1 top-1 h-4 w-4", AppConfig.HasUnreadAchievements(HttpContext?.User.GetUserName()) ? "text-red-500" : "text-transparent") viewBox="0 0 32 32"><circle cx="16" cy="16" r="8" fill="currentColor"/></svg>
7573
</div>
7674
<div id="achievements-menu"></div>
7775
</li>

MyApp/wwwroot/css/app.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,10 +1369,6 @@ select{
13691369
height: 100%;
13701370
}
13711371

1372-
.h-\[20rem\] {
1373-
height: 20rem;
1374-
}
1375-
13761372
.max-h-24 {
13771373
max-height: 6rem;
13781374
}

MyApp/wwwroot/lib/js/default.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,21 @@ if (clearMetadata) {
3131
})
3232
}
3333

34+
function highlightElement(id) {
35+
const el = document.getElementById(id)
36+
if (el) {
37+
el.classList.add('highlighted')
38+
el.scrollIntoView('smooth')
39+
}
40+
}
41+
3442
if (location.hash) {
35-
setTimeout(() => {
36-
const el = document.getElementById(location.hash.substring(1))
37-
if (el) {
38-
el.classList.add('highlighted')
39-
el.scrollIntoView('smooth')
43+
highlightElement(location.hash.substring(1))
44+
}
45+
46+
document.addEventListener('DOMContentLoaded', () =>
47+
Blazor.addEventListener('enhancedload', (e) => {
48+
if (location.hash) {
49+
highlightElement(location.hash.substring(1))
4050
}
41-
}, 500)
42-
}
51+
}))

MyApp/wwwroot/mjs/dtos.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Options:
2-
Date: 2024-04-06 11:14:32
2+
Date: 2024-04-06 13:26:31
33
Version: 8.22
44
Tip: To override a DTO option, remove "//" prefix before updating
55
BaseUrl: https://localhost:5001
@@ -350,12 +350,14 @@ export class Notification {
350350
/** @type {?string} */
351351
refUserName;
352352
}
353-
/** @typedef {'Unknown'|'AnswerUpVote'|'AnswerDownVote'|'QuestionUpVote'|'QuestionDownVote'} */
353+
/** @typedef {'Unknown'|'NewAnswer'|'AnswerUpVote'|'AnswerDownVote'|'NewQuestion'|'QuestionUpVote'|'QuestionDownVote'} */
354354
export var AchievementType;
355355
(function (AchievementType) {
356356
AchievementType["Unknown"] = "Unknown"
357+
AchievementType["NewAnswer"] = "NewAnswer"
357358
AchievementType["AnswerUpVote"] = "AnswerUpVote"
358359
AchievementType["AnswerDownVote"] = "AnswerDownVote"
360+
AchievementType["NewQuestion"] = "NewQuestion"
359361
AchievementType["QuestionUpVote"] = "QuestionUpVote"
360362
AchievementType["QuestionDownVote"] = "QuestionDownVote"
361363
})(AchievementType || (AchievementType = {}));

0 commit comments

Comments
 (0)