Skip to content

Conversation

nikhen-s
Copy link

@nikhen-s nikhen-s commented Jul 1, 2025

Main Changes

  • Added Testimonials Tab and Table
  • Added courses and testimonials backend

Work in progress

@nikhen-s nikhen-s marked this pull request as ready for review September 13, 2025 11:22
@yutotakano yutotakano self-requested a review September 13, 2025 13:19
Copy link
Member

@yutotakano yutotakano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the awesome feature! There are several points I'd like to request changes or comments on, so I'd appreciate it if you could iterate on it when you have the time.

Major points are:

  • I would prefer not to expose the category ID to the frontend. It's generally not good practice to expose raw DB IDs and slugs are perfectly equivalent for all the use cases of this PR
  • Notification emails are broken as it currently stands
  • Every user can currently see every testimonial, including rejected ones by someone else (in the network request)
  • Some React and SQL optimizations and code style suggestions; a lot of the code feels very imperative (React is mostly suited for functional programming) and triggers unnecessary re-renders
  • Mantine Datatable doesn't feel necessary

I'm aware there are lot of things I've left comments on... apologies! I'll be honest a lot of the code is currently a little messy and I wouldn't want that merged in just yet. It shouldn't be very hard to fix though!

If you don't have time because of your job etc, then don't worry; feel free to say and someone else (maybe me) can pick it up :)



class Category(models.Model):
id = models.AutoField(primary_key=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The slug acts as the user-friendly unique ID for categories, and I'd prefer not to send raw database IDs to the frontend since it's not good practice. This PR looks like it can be entirely written with slugs, so could we do that?

from util import response, func_cache


@response.request_get()
Copy link
Member

@yutotakano yutotakano Sep 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove category_id from this endpoint, then the result is fairly similar to list_categories right below. Instead of creating a duplicate endpoint, it would be shorter to merge the two, basically adding an optional query parameter to list_categories, like files.betterinformatics.com/api/categories/list/?include_euclid_codes=true.

"category_id": cat.id,
"displayname": cat.displayname,
"slug": cat.slug,
"euclid_codes": [euclidcode.code for euclidcode in cat.euclid_codes.all()]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is likely going to be pretty slow, since we're doing one DB query for every row returned from Category.objects.all().

I would suggest to use

categories = Category.objects.prefetch_related("euclid_codes") [...]

which under the hood will do an SQL JOIN, so everything is fetched in one query.

categories = Category.objects.select_related("meta").order_by("displayname").all()
res = [
{
"category_id": cat.id,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest removing this in favour of slug.


def get_category_data(request, cat):
res = {
"category_id": cat.id,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removal

"clsx": "^2.1.0",
"clsx": "^2.1.1",
"date-fns": "^3.3.0",
"dayjs": "^1.11.13",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have date-fns, what is the dayjs dependency used for and can we replace it with date-fns?

"@mantine/form": "^8.1.2",
"@mantine/hooks": "^8.0.0",
"@tabler/icons-react": "^3.0.0",
"@mantine/hooks": "^8.1.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The various Mantine package versions don't appear to be consistent with each other. This is bad, since Mantine packages are released in tandem and have compatibility issues if you combine multiple versions. If we're sticking to 8.2.1, everything should be 8.2.1.

But honestly, if we aren't relying on anything new, sticking with ^8.0.0 would be better. This is because the upstream repository (Community-Solutions at ETH) uses ^8.0.0 and it would make maintenance easier if they were aligned.

"jwt-decode": "^4.0.0",
"katex": "^0.16.9",
"lodash-es": "^4.17.21",
"mantine-datatable": "^8.2.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% convinced that we need mantine-datatable for the testimonials list.

None of the columns except "number of testimonials" and "course name" really need sorting, so it's probably more lightweight to implement it on our own. It's not a particularly large and heavy table either, since there are only O(category_count) number of rows, not O(testimonial_count) rows. Normal Mantine table should be able to cope perfectly fine with such amount.

What do you think?


</Modal>

<Card withBorder={true} radius="md" p={"lg"} style={{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p="lg" is conflicting with "padding: 8px" right below. Please be consistent with the styling, and prefer the JSX props approach where possible. If complex inline styles are needed, I suggest moving them into CSS modules.

NEW_COMMENT_TO_COMMENT = 2
NEW_ANSWER_TO_ANSWER = 3
NEW_COMMENT_TO_DOCUMENT = 4
UPDATE_TO_TESTIMONIAL_APPROVAL_STATUS = 5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth creating a custom DB migration to enable this setting for everyone by default. In auth_backend.py I see you've edited the default setting for new users, but existing users (which there are over a thousand on BI) will not default to receiving notifications.

The migration should create a NotificationSetting with UPDATE_TO_TESTIMONIAL_APPROVAL_STATUS for every existing user.

It might be worth having a reverse migration too, but I'm not sure what the correct semantics should be. Maybe delete every row that has UPDATE_TO_TESTIMONIAL_APPROVAL_STATUS?

@nikhen-s
Copy link
Author

nikhen-s commented Sep 15, 2025

Thanks for the detailed review @yutotakano ! No worries at all, I'm happy to make the changes requested, and can slowly do it over the next week or two.

@yutotakano
Copy link
Member

Awesome!! If you have thoughts or disagree with any of my comments during development, let me know. Maybe your ideas are better :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants