This summer, I got an opportunity to collaborate with UGA's sociology department to build a unique website. The goal was to host a survey to students that was scored in realtime and provided a unique feedback towards the end. It would allow us to understand the co-relation between an individual's happiness levels and choices they make in life. It also would act as a learning tool for their class called 'Science of Happiness'.
In a much broader sense, the goal was to make the survey simple and intuitive while keeping it engaging. So I turned to SvelteKit as my frontend engine. The website was built with very little assumptions and was kept as dynamic as possible. Changing one line in a JSON document and voila, those changes would instantly update the website contents and UI.
In this blog, I would break down the logic used to build this website and share my learnings along the way.
If you are already impatient, you can check the website and it's code repo.
The user journey was pretty straightforward in this one -
- The user would sign up using their college email
- They will answer a few demographic questions for the first time they log in
- They will then proceed to answer the survey
- Finishing the survey will take them to the results page
- In future we will also allow the users to view their past submissions and compare the results
User
{
_id: ObjectId("64f0a6dee4f69996a883d9a3"),
email: 'kevin.jain@uga.edu',
name: 'Kevin',
createdAt: ISODate("2023-08-31T14:42:38.526Z"),
demographic: {
'1': '2',
'2': '5',
...
'n': 'm'
}
}
Submission
{
_id: ObjectId("64e789c68ffd676e4cdd062b"),
user: ObjectId("64e788f08ffd676e4cdd0613"),
completed: true,
createdAt: ISODate("2023-08-24T16:48:06.402Z"),
answers: {
'1': 2,
'2': 2,
...
'10': '15,13,3,9,21,17,7,25,6,22',
},
scores: {
'1': 2,
'2': 2,
...
'10': 1.5384615384615385,
},
results: {
score: 29.8,
max_score: 4000,
total_weight: 37,
effective_weight: 108,
effective_score: 3218,
standardized_score: 3.22
},
feedback: 'You are engaging in many activities and displaying many attitudes that are strongly related to happiness and wellbeing! However, ...'
}
A submission is tied to it's users' ID, it has a completed
flag which indicates if the user has finished answering all questions, and it has a couple other attributes like scores
, results
and feedback
which are calculated by our backend scoring logic.
The questions are the meat of the website, each question is unique and the web page uses the context provided by the backend to populate its UI.
So, a question in JSON format that looks like this --
{
id: 1,
question: "On average, how many hours of sleep do you get per night?",
options: [
{ id: 1, option: "Less than 6", score: 0 },
{ id: 2, option: "6-7", score: 0.5 },
{ id: 3, option: "7-9", score: 1 },
{ id: 4, option: "9-10", score: 0.5 },
{ id: 5, option: "More than 10", score: 0 }
],
images: ["img-url-1, img-url-2, img-url-3, ... img-url-n"],
weight: 1,
multiple: false, // boolean to indicate if there are multiple questions in one
type: "radio", // [radio, checkbox]
format: "text", // [plain-text, images, cards]
required: true // if the question is compulsory to answer
},
Will produce a webpage that looks like this ---
Another question that has the following data --
{
id: 8,
title: "On average...",
format: "text",
questions: [{ id: 1, q: "How many hours per week do you socialize face-to-face with family members?", sign: 1 },
{ id: 2, q: "How many hours per week do you socialize face-to-face with friends?", sign: 1 },
{ id: 3, q: "How many close friends do you have that you socialize with regularly?", sign: 1 }],
images: ["img-url-1, img-url-2, img-url-3, ... img-url-n"],
multiple: true,
weight: 1,
type: "range",
min: 0,
max: 10,
step: 1,
required: true,
}
Will look like this --
Another example --
{
id: 10,
question: "Take a moment to consider each image and select 10 images that closely depict things that you most associate with happiness",
format: "image",
maxSelections: 10, // Exact number of selections that a user has to make //
options: [
{ id: 1, score: 1, url: "img-ur-1" },
{ id: 2, score: 1, url: "img-ur-1" },
...
{ id: n, score: 0, url: "img-ur-n" },
],
type: "checkbox",
required: true,
weight: 1,
multiple: false
}
Will look like this --
You get the gist!
All the questions have a parent question, sub questions (if any), all possible options and their types (checkbox, range, radio) and the scores associated with those options. The user will be able to track the progress via visual tracker and there will be a carousel of images on the top that will provide more context to each question. Each selection made by the user will be stored inside the submission
document in the database.
That's all we need from our frontend. Upon submission, the user will see a results section.
The admin can go and add new questions, modify existing ones, and the website will automagically update the views to support it! I will cover how the scoring logic works on the backend side in the next blog post. Meanwhile you can check the frontend code on my GitHub repo and shoot me an email on thatskevinjain@gmail.com for suggestions/questions.
Happy coding!