updated with secrets
This commit is contained in:
parent
32796f996e
commit
ebc6d25920
@ -1,6 +1,12 @@
|
|||||||
PAGE_TITLE = "ARQ Usage Survey"
|
PAGE_TITLE = "ARQ Usage Survey"
|
||||||
|
|
||||||
USAGE_FREQUENCY_OPTIONS = ["daily", "weekly", "monthly", "Never used it"]
|
USAGE_FREQUENCY_OPTIONS = [
|
||||||
|
"Multiple times a day",
|
||||||
|
"Multiple times a week",
|
||||||
|
"A few times a month",
|
||||||
|
"Tried once or twice",
|
||||||
|
"Never used it",
|
||||||
|
]
|
||||||
|
|
||||||
TASK_OPTIONS = {
|
TASK_OPTIONS = {
|
||||||
"analysis": "Stock Analysis",
|
"analysis": "Stock Analysis",
|
||||||
|
|||||||
331
secret_survey.py
331
secret_survey.py
@ -1,45 +1,55 @@
|
|||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import secrets
|
import os
|
||||||
|
|
||||||
from nicegui import app, ui
|
from nicegui import app, ui
|
||||||
|
|
||||||
|
import constants as const
|
||||||
|
|
||||||
# --- 1. User Database & Token Generation ---
|
# --- 1. User Database & Token Generation ---
|
||||||
# In a real app, you'd save these to a file or DB.
|
# In a real app, you'd save these to a file or DB.
|
||||||
# Generating unique tokens for your three users:
|
# Generating unique tokens for your three users:
|
||||||
USER_MAP = {"k9a2_xJv1": "Ken", "Lz78_pQn9": "Liz", "Rb55_mTk2": "Ruben"}
|
# USER_MAP = {"k9a2_xJv1": "Ken", "Lz78_pQn9": "Liz", "Rb55_mTk2": "Ruben"}
|
||||||
|
|
||||||
# --- Survey Options & State ---
|
with open("user_secrets.json") as f:
|
||||||
FREQUENCY_OPTIONS = ["Daily", "Weekly", "Monthly", "Rarely"]
|
SECRETS = json.load(f)
|
||||||
FEATURE_OPTIONS = ["News Feed", "Marketplace", "Groups", "Messenger", "Stories"]
|
|
||||||
OTHER_APP_OPTIONS = ["Instagram", "TikTok", "X/Twitter", "LinkedIn", "Snapchat", "Reddit"]
|
|
||||||
GENDER_OPTIONS = ["Male", "Female", "Non-binary", "Prefer not to say"]
|
|
||||||
|
|
||||||
|
|
||||||
class SurveyState:
|
class SurveyState:
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.user_name = name
|
self.user_name = name
|
||||||
self.frequency = None
|
self.frequency = None
|
||||||
|
self.no_use_reason = ""
|
||||||
self.selected_features = []
|
self.selected_features = []
|
||||||
|
self.other_tasks = ""
|
||||||
self.feature_feedback = {}
|
self.feature_feedback = {}
|
||||||
self.age = None
|
self.suggestions = ""
|
||||||
self.gender = None
|
self.priority_tasks = []
|
||||||
self.location = ""
|
|
||||||
|
def convert_to_json(self):
|
||||||
|
return {
|
||||||
|
"name": self.user_name,
|
||||||
|
"usage": {
|
||||||
|
"frequency": self.frequency,
|
||||||
|
"Reason for not using": self.no_use_reason,
|
||||||
|
"features_used": self.selected_features,
|
||||||
|
"other_tasks": self.other_tasks,
|
||||||
|
},
|
||||||
|
"feature_feedback": self.feature_feedback,
|
||||||
|
"suggestions": self.suggestions,
|
||||||
|
"priority_tasks": self.priority_tasks,
|
||||||
|
}
|
||||||
|
|
||||||
def save_to_json(self):
|
def save_to_json(self):
|
||||||
data = {
|
data = self.convert_to_json()
|
||||||
"user": self.user_name,
|
with open(f"results/response_{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.json", "w") as f:
|
||||||
"usage": {"frequency": self.frequency, "features_used": self.selected_features},
|
|
||||||
"feature_feedback": self.feature_feedback,
|
|
||||||
"demographics": {"age": self.age, "gender": self.gender, "location": self.location},
|
|
||||||
}
|
|
||||||
filename = f"survey_{self.user_name.lower()}.json"
|
|
||||||
with open(filename, "w") as f:
|
|
||||||
json.dump(data, f, indent=4)
|
json.dump(data, f, indent=4)
|
||||||
|
|
||||||
|
|
||||||
# --- 2. The Main Page Function ---
|
# --- 2. The Main Page Function ---
|
||||||
@ui.page("/")
|
@ui.page("/")
|
||||||
def main_page(token: str):
|
def main_page(token: str = None):
|
||||||
# Extract 'id' from the URL query parameters
|
# Extract 'id' from the URL query parameters
|
||||||
# user_token = app.native.main_window.get_url() if hasattr(app, "native") else ""
|
# user_token = app.native.main_window.get_url() if hasattr(app, "native") else ""
|
||||||
# Standard way in web mode:
|
# Standard way in web mode:
|
||||||
@ -51,7 +61,7 @@ def main_page(token: str):
|
|||||||
ui.label("Please check your unique link and try again.").classes("text-grey")
|
ui.label("Please check your unique link and try again.").classes("text-grey")
|
||||||
return
|
return
|
||||||
|
|
||||||
if token not in USER_MAP:
|
if token not in [i["token"] for i in SECRETS]:
|
||||||
with ui.column().classes("w-full items-center mt-20"):
|
with ui.column().classes("w-full items-center mt-20"):
|
||||||
ui.icon("error", color="red").classes("text-6xl")
|
ui.icon("error", color="red").classes("text-6xl")
|
||||||
ui.label("User not found").classes("text-h4 text-negative")
|
ui.label("User not found").classes("text-h4 text-negative")
|
||||||
@ -59,7 +69,20 @@ def main_page(token: str):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Valid User Found
|
# Valid User Found
|
||||||
user_name = USER_MAP[token]
|
user_name = [i["username"] for i in SECRETS if i["token"] == token][0]
|
||||||
|
|
||||||
|
# Check if user has already answered
|
||||||
|
files = os.listdir("results")
|
||||||
|
for file in files:
|
||||||
|
with open(f"results/{file}") as f:
|
||||||
|
response = json.load(f)
|
||||||
|
if response.get("name") == user_name:
|
||||||
|
with ui.column().classes("w-full items-center mt-20"):
|
||||||
|
ui.icon("check", color="green").classes("text-6xl")
|
||||||
|
ui.label("You have already filled the survey!").classes("text-h4 text-positive")
|
||||||
|
ui.label("Thank You!").classes("text-grey")
|
||||||
|
return
|
||||||
|
|
||||||
state = SurveyState(user_name)
|
state = SurveyState(user_name)
|
||||||
container = ui.column().classes("w-full items-center q-pa-md")
|
container = ui.column().classes("w-full items-center q-pa-md")
|
||||||
|
|
||||||
@ -68,84 +91,227 @@ def main_page(token: str):
|
|||||||
container.clear()
|
container.clear()
|
||||||
with container:
|
with container:
|
||||||
ui.label(f"Welcome, {state.user_name}!").classes("text-h3 text-primary mb-2")
|
ui.label(f"Welcome, {state.user_name}!").classes("text-h3 text-primary mb-2")
|
||||||
ui.label("Facebook Usage Survey").classes("text-h5 mb-6 text-grey-7")
|
ui.label("ARQ Usage").classes("text-h4 mb-4")
|
||||||
|
|
||||||
with ui.card().classes("w-full max-w-lg p-6"):
|
with ui.card().classes("w-full max-w-lg p-6"):
|
||||||
ui.label("How frequently do you use Facebook?").classes("text-bold")
|
ui.label("How frequently do you use ARQ?").classes("text-bold")
|
||||||
ui.radio(options=FREQUENCY_OPTIONS).bind_value(state, "frequency")
|
p1_radio = ui.radio(options=const.USAGE_FREQUENCY_OPTIONS).bind_value(state, "frequency")
|
||||||
|
|
||||||
ui.label("What features do you use?").classes("text-bold mt-4")
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
ui.select(options=FEATURE_OPTIONS, multiple=True).classes("w-full").bind_value(
|
p1_radio, "value", backward=lambda v: v == "Never used it"
|
||||||
state, "selected_features"
|
):
|
||||||
|
ui.label("What are the reasons for not using ARQ?")
|
||||||
|
no_use_reason = (
|
||||||
|
ui.input(validation={"Minimum 20 characters": lambda value: len(value) >= 20})
|
||||||
|
.classes("w-full")
|
||||||
|
.bind_value(state, "no_use_reason")
|
||||||
|
)
|
||||||
|
|
||||||
|
ui.label("What tasks have you performed using this app?").classes("text-bold mt-4")
|
||||||
|
p1_select = (
|
||||||
|
ui.select(options=const.TASK_OPTIONS, multiple=True)
|
||||||
|
.props("use-chips")
|
||||||
|
.classes("w-full")
|
||||||
|
.bind_value(state, "selected_features")
|
||||||
)
|
)
|
||||||
|
|
||||||
next_btn = ui.button("Next", on_click=show_page_2).classes("mt-6 w-full")
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
p1_select, "value", backward=lambda v: "Others" in v
|
||||||
|
):
|
||||||
|
ui.label("What other tasks have you performed using ARQ?")
|
||||||
|
ui.input().classes("w-full").bind_value(state, "other_tasks")
|
||||||
|
|
||||||
ui.timer(
|
with ui.row().classes("w-full"):
|
||||||
0.5, lambda: next_btn.set_enabled(state.frequency is not None and len(state.selected_features) > 0)
|
next_btn = ui.button("Next", on_click=show_page_2).classes("mt-6 w-full")
|
||||||
)
|
ui.tooltip(
|
||||||
|
"Please answer all questions (min 20 chars for 'Reasons for failure')"
|
||||||
|
).bind_visibility_from(next_btn, "enabled", backward=lambda v: not v)
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
def enable_next():
|
||||||
|
if p1_radio.value == "Never used it":
|
||||||
|
if len(no_use_reason.value) < 20:
|
||||||
|
return False
|
||||||
|
return state.frequency is not None and len(state.selected_features) > 0
|
||||||
|
|
||||||
|
ui.timer(0.1, lambda: next_btn.set_enabled(enable_next()))
|
||||||
|
|
||||||
# --- PAGE 2: STAR RATINGS (With fix for terminal errors) ---
|
# --- PAGE 2: STAR RATINGS (With fix for terminal errors) ---
|
||||||
def show_page_2():
|
def show_page_2():
|
||||||
container.clear()
|
container.clear()
|
||||||
|
# Initialize dictionary for selected features
|
||||||
for f in state.selected_features:
|
for f in state.selected_features:
|
||||||
|
if f == "Others":
|
||||||
|
continue
|
||||||
if f not in state.feature_feedback:
|
if f not in state.feature_feedback:
|
||||||
state.feature_feedback[f] = {"rating": 5, "likes": "", "other_apps": [], "improvements": ""}
|
state.feature_feedback[f] = {
|
||||||
|
"completed_on_arq": None,
|
||||||
|
"rating": 0,
|
||||||
|
"low_rating_suggestions": "",
|
||||||
|
"completed_how": None,
|
||||||
|
"arq_helped": [],
|
||||||
|
"excel_features": [],
|
||||||
|
"other_apps": "",
|
||||||
|
"abandoned_why": [],
|
||||||
|
"abandoned_why_others": "",
|
||||||
|
}
|
||||||
|
|
||||||
with container:
|
with container:
|
||||||
ui.label("Feature Feedback").classes("text-h4 mb-4")
|
ui.label("Feature Feedback").classes("text-h4 mb-4")
|
||||||
|
|
||||||
|
# We define the button and validation logic first to ensure they are in scope
|
||||||
def is_page_2_valid():
|
def is_page_2_valid():
|
||||||
for f in state.selected_features:
|
valid = True
|
||||||
d = state.feature_feedback[f]
|
for f, ob in state.feature_feedback.items():
|
||||||
if d["rating"] < 4 and len(d.get("improvements", "")) < 20:
|
if ob["completed_on_arq"] is None:
|
||||||
return False
|
valid = False
|
||||||
return True
|
if ob["completed_on_arq"] == "Yes" and ob["rating"] == 0:
|
||||||
|
valid = False
|
||||||
|
if ob["completed_on_arq"] == "No" and ob["completed_how"] is None:
|
||||||
|
valid = False
|
||||||
|
if ob["completed_how"] == "both" and not ob["arq_helped"]:
|
||||||
|
valid = False
|
||||||
|
if ob["completed_how"] in ["both", "excel"] and not ob["excel_features"]:
|
||||||
|
valid = False
|
||||||
|
if ob["completed_how"] == "abandoned" and not ob["abandoned_why"]:
|
||||||
|
valid = False
|
||||||
|
if ob["completed_how"] == "other" and not ob["other_apps"]:
|
||||||
|
valid = False
|
||||||
|
return valid
|
||||||
|
|
||||||
for feature in state.selected_features:
|
for feature in state.selected_features:
|
||||||
|
if feature == "Others":
|
||||||
|
continue
|
||||||
with ui.card().classes("w-full max-w-lg p-6 mb-4"):
|
with ui.card().classes("w-full max-w-lg p-6 mb-4"):
|
||||||
ui.label(f"Rate the {feature}").classes("text-h6 text-primary")
|
ui.label(f"{const.TASK_OPTIONS[feature]}").classes("text-h6 text-primary")
|
||||||
stars = (
|
|
||||||
ui.rating(value=5, icon="star")
|
ui.label("Were you able to complete this task on ARQ").classes("text-bold mt-4")
|
||||||
.classes("text-3xl")
|
p2q1_select = (
|
||||||
.bind_value(state.feature_feedback[feature], "rating")
|
ui.radio(["Yes", "No"])
|
||||||
|
.props("inline")
|
||||||
|
.bind_value(state.feature_feedback[feature], "completed_on_arq")
|
||||||
)
|
)
|
||||||
|
|
||||||
with ui.column().classes("w-full").bind_visibility_from(stars, "value", backward=lambda v: v >= 4):
|
# Star Rating (Quasar based)
|
||||||
ui.textarea("What do you like about it?").classes("w-full").bind_value(
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
state.feature_feedback[feature], "likes"
|
p2q1_select, "value", backward=lambda v: v == "Yes"
|
||||||
|
):
|
||||||
|
ui.label("How would you rate the features available to complete this task").classes(
|
||||||
|
"text-bold mt-4"
|
||||||
|
)
|
||||||
|
rating = (
|
||||||
|
ui.rating(value=5, icon="star")
|
||||||
|
.classes("text-3xl")
|
||||||
|
.bind_value(state.feature_feedback[feature], "rating")
|
||||||
|
)
|
||||||
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
rating, "value", backward=lambda v: 0 < v < 4
|
||||||
|
):
|
||||||
|
ui.input(label="What could have been improved for a better experience?").bind_value(
|
||||||
|
state.feature_feedback[feature], "low_rating_suggestions"
|
||||||
|
).classes("w-full")
|
||||||
|
|
||||||
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
p2q1_select, "value", backward=lambda v: v == "No"
|
||||||
|
):
|
||||||
|
ui.label("How did you complete this task?")
|
||||||
|
p2q2_select = (
|
||||||
|
ui.radio(
|
||||||
|
options={
|
||||||
|
"both": "Using both ARQ and Excel",
|
||||||
|
"excel": "Entirely on Excel",
|
||||||
|
"other": "Using other applications",
|
||||||
|
"abandoned": "Task abandoned",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.props("inline")
|
||||||
|
.bind_value(state.feature_feedback[feature], "completed_how")
|
||||||
)
|
)
|
||||||
|
|
||||||
with ui.column().classes("w-full").bind_visibility_from(stars, "value", backward=lambda v: v < 4):
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
ui.label("Other apps you use:").classes("text-caption")
|
p2q2_select, "value", backward=lambda v: v == "both"
|
||||||
ui.select(options=OTHER_APP_OPTIONS, multiple=True).classes("w-full").bind_value(
|
):
|
||||||
state.feature_feedback[feature], "other_apps"
|
ui.label("How did ARQ help you with this task?")
|
||||||
|
ui.select(options=const.ARQ_HELPED, multiple=True).props("use-chips").classes(
|
||||||
|
"w-full"
|
||||||
|
).bind_value(state.feature_feedback[feature], "arq_helped")
|
||||||
|
|
||||||
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
p2q2_select, "value", backward=lambda v: v == "both" or v == "excel"
|
||||||
|
):
|
||||||
|
ui.label("Which Excel features did you require to complete this task?")
|
||||||
|
ui.select(options=const.EXCEL_FEATURE_LIST, multiple=True).props("use-chips").classes(
|
||||||
|
"w-full"
|
||||||
|
).bind_value(state.feature_feedback[feature], "excel_features")
|
||||||
|
|
||||||
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
p2q2_select, "value", backward=lambda v: v == "other"
|
||||||
|
):
|
||||||
|
ui.input(label="Which other applications helped you with this task?").classes(
|
||||||
|
"w-full"
|
||||||
|
).bind_value(state.feature_feedback[feature], "other_apps")
|
||||||
|
|
||||||
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
p2q2_select, "value", backward=lambda v: v == "abandoned"
|
||||||
|
):
|
||||||
|
ui.label("What were the reasons for abandoning this task?")
|
||||||
|
p2q3_select = (
|
||||||
|
ui.select(options=const.ABANDONMENT_OPTIONS, multiple=True)
|
||||||
|
.props("use-chips")
|
||||||
|
.classes("w-full")
|
||||||
|
.bind_value(state.feature_feedback[feature], "abandoned_why")
|
||||||
)
|
)
|
||||||
ui.textarea("Improvements (min 20 characters)").classes("w-full").bind_value(
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
state.feature_feedback[feature], "improvements"
|
p2q3_select, "value", backward=lambda v: "others" in v
|
||||||
|
):
|
||||||
|
ui.input(label="Describe the reasons for abandoning this task?").classes("w-full").bind_value(
|
||||||
|
state.feature_feedback[feature], "abandoned_why_others"
|
||||||
)
|
)
|
||||||
|
|
||||||
with ui.row().classes("w-full max-w-lg justify-between mt-4"):
|
with ui.row().classes("w-full max-w-lg justify-between mt-4"):
|
||||||
ui.button("Back", on_click=show_page_1).props("outline")
|
ui.button("Back", on_click=show_page_1).props("outline")
|
||||||
next_btn = ui.button("Next", on_click=show_page_3)
|
next_btn = ui.button("Next", on_click=show_page_3)
|
||||||
ui.tooltip("Please answer all questions fully").bind_visibility_from(
|
ui.tooltip("Please answer all questions").bind_visibility_from(
|
||||||
next_btn, "enabled", backward=lambda v: not v
|
next_btn, "enabled", backward=lambda v: not v
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Reactive validation timer
|
||||||
ui.timer(0.5, lambda: next_btn.set_enabled(is_page_2_valid()))
|
ui.timer(0.5, lambda: next_btn.set_enabled(is_page_2_valid()))
|
||||||
|
|
||||||
# --- PAGE 3: DEMOGRAPHICS ---
|
# --- PAGE 3: DEMOGRAPHICS ---
|
||||||
def show_page_3():
|
def show_page_3():
|
||||||
container.clear()
|
container.clear()
|
||||||
with container:
|
with container:
|
||||||
ui.label("Demographics").classes("text-h4 mb-4")
|
ui.label("Final thoughts").classes("text-h4 mb-4")
|
||||||
with ui.card().classes("w-full max-w-lg p-6"):
|
with ui.card().classes("w-full max-w-lg p-6"):
|
||||||
ui.number("Age", format="%d").classes("w-full").bind_value(state, "age")
|
suggestions = (
|
||||||
ui.select(label="Gender", options=GENDER_OPTIONS).classes("w-full").bind_value(state, "gender")
|
ui.textarea("Do you have any suggestions for the app")
|
||||||
ui.input("Location").classes("w-full").bind_value(state, "location")
|
.classes("w-full")
|
||||||
|
.bind_value(state, "suggestions")
|
||||||
|
)
|
||||||
|
ui.label("Select exactly 2 features to prioritize:")
|
||||||
|
priority_tasks = (
|
||||||
|
ui.select(
|
||||||
|
options=const.PRIORITY_TASKS,
|
||||||
|
multiple=True,
|
||||||
|
validation={"Please select only 2 features": lambda value: len(value) <= 2},
|
||||||
|
)
|
||||||
|
.props("use-chips")
|
||||||
|
.classes("w-full")
|
||||||
|
.bind_value(state, "priority_tasks")
|
||||||
|
)
|
||||||
|
|
||||||
with ui.row().classes("w-full justify-between mt-6"):
|
with ui.row().classes("w-full justify-between mt-6"):
|
||||||
ui.button("Back", on_click=show_page_2).props("outline")
|
ui.button("Back", on_click=show_page_2).props("outline")
|
||||||
ui.button("Review Survey", on_click=show_confirmation).classes("bg-blue")
|
next_btn = ui.button("Review Survey", on_click=show_confirmation).classes("bg-blue")
|
||||||
|
ui.tooltip("Please answer all questions").bind_visibility_from(
|
||||||
|
next_btn, "enabled", backward=lambda v: not v
|
||||||
|
)
|
||||||
|
|
||||||
|
ui.timer(
|
||||||
|
0.5,
|
||||||
|
lambda: next_btn.set_enabled(len(state.suggestions) > 0 and len(state.priority_tasks) == 2),
|
||||||
|
)
|
||||||
|
|
||||||
# --- PAGE 4: CONFIRMATION ---
|
# --- PAGE 4: CONFIRMATION ---
|
||||||
def show_confirmation():
|
def show_confirmation():
|
||||||
@ -154,14 +320,36 @@ def main_page(token: str):
|
|||||||
ui.label("Review Your Answers").classes("text-h4 mb-4")
|
ui.label("Review Your Answers").classes("text-h4 mb-4")
|
||||||
with ui.card().classes("w-full max-w-2xl p-6"):
|
with ui.card().classes("w-full max-w-2xl p-6"):
|
||||||
with ui.column().classes("w-full gap-2"):
|
with ui.column().classes("w-full gap-2"):
|
||||||
ui.label(f"**Name:** {state.user_name}")
|
ui.markdown(f"**Frequency**: {state.frequency}")
|
||||||
ui.label(f"**Frequency:** {state.frequency}")
|
if state.no_use_reason:
|
||||||
ui.separator()
|
ui.markdown(f"**Reasons for not using**: {state.no_use_reason}")
|
||||||
for f in state.selected_features:
|
feature_text = ", ".join(const.TASK_OPTIONS[i] for i in state.selected_features if i != "Others")
|
||||||
d = state.feature_feedback[f]
|
feature_text += f", {state.other_tasks}" if state.other_tasks else ""
|
||||||
ui.label(f"**{f}**: {d['rating']} Stars")
|
ui.markdown(f"**Features**: {feature_text}")
|
||||||
ui.separator()
|
|
||||||
ui.label(f"**Location:** {state.location}")
|
ui.markdown(f"**Suggestions**: {state.suggestions}")
|
||||||
|
ui.markdown(f"**Priority**: {', '.join(state.priority_tasks)}")
|
||||||
|
|
||||||
|
ui.separator().classes("my-2")
|
||||||
|
|
||||||
|
with ui.column().classes("w-full gap-2"):
|
||||||
|
ui.markdown("#### Your feedback for tasks")
|
||||||
|
for fe, fd in state.feature_feedback.items():
|
||||||
|
ui.markdown(f"##### {const.TASK_OPTIONS[fe]}")
|
||||||
|
if fd["completed_on_arq"] == "Yes":
|
||||||
|
ui.markdown(f"**Rating**: {fd['rating']}")
|
||||||
|
if fd["low_rating_suggestions"]:
|
||||||
|
ui.markdown(f"**Suggestions**: {fd['low_rating_suggestions']}")
|
||||||
|
if fd["arq_helped"]:
|
||||||
|
ui.markdown(f"**Arq helped**: {', '.join(fd['arq_helped'])}")
|
||||||
|
if fd["excel_features"]:
|
||||||
|
ui.markdown(f"**Excel features used**: {', '.join(fd['excel_features'])}")
|
||||||
|
if fd["other_apps"]:
|
||||||
|
ui.markdown(f"**Other apps used**: {fd['other_apps']}")
|
||||||
|
if fd["abandoned_why"]:
|
||||||
|
ui.markdown(f"**Task abandoned becuase**: {', '.join(fd['abandoned_why'])}")
|
||||||
|
if fd["abandoned_why_others"]:
|
||||||
|
ui.markdown(f"**Task abandoned becuase**: {fd['abandoned_why_others']}")
|
||||||
|
|
||||||
with ui.row().classes("w-full justify-between mt-8"):
|
with ui.row().classes("w-full justify-between mt-8"):
|
||||||
ui.button("Back to Edit", on_click=show_page_3).props("outline")
|
ui.button("Back to Edit", on_click=show_page_3).props("outline")
|
||||||
@ -178,5 +366,18 @@ def main_page(token: str):
|
|||||||
|
|
||||||
show_page_1()
|
show_page_1()
|
||||||
|
|
||||||
|
with ui.right_drawer(value=True, fixed=True).classes("bg-blue-50 p-4").props("elevated width=450") as right_drawer:
|
||||||
|
|
||||||
|
ui.label("Live Response Tracker").classes("text-grey font-bold")
|
||||||
|
debug_display = ui.markdown().classes("font-mono w-full")
|
||||||
|
|
||||||
|
def update_debug():
|
||||||
|
# Convert dictionary to a pretty-printed JSON string wrapped in markdown code blocks
|
||||||
|
data = state.convert_to_json()
|
||||||
|
formatted_json = json.dumps(data, indent=2)
|
||||||
|
debug_display.content = f"```json\n{formatted_json}\n```"
|
||||||
|
|
||||||
|
ui.timer(0.1, update_debug)
|
||||||
|
|
||||||
|
|
||||||
ui.run()
|
ui.run()
|
||||||
|
|||||||
21
survey.py
21
survey.py
@ -26,11 +26,11 @@ class SurveyState:
|
|||||||
return {
|
return {
|
||||||
"usage": {
|
"usage": {
|
||||||
"frequency": self.frequency,
|
"frequency": self.frequency,
|
||||||
|
"Reason for not using": self.no_use_reason,
|
||||||
"features_used": self.selected_features,
|
"features_used": self.selected_features,
|
||||||
"other_tasks": self.other_tasks,
|
"other_tasks": self.other_tasks,
|
||||||
},
|
},
|
||||||
"feature_feedback": self.feature_feedback,
|
"feature_feedback": self.feature_feedback,
|
||||||
"Reason for not using": self.no_use_reason,
|
|
||||||
"suggestions": self.suggestions,
|
"suggestions": self.suggestions,
|
||||||
"priority_tasks": self.priority_tasks,
|
"priority_tasks": self.priority_tasks,
|
||||||
}
|
}
|
||||||
@ -107,6 +107,7 @@ def create_survey():
|
|||||||
state.feature_feedback[f] = {
|
state.feature_feedback[f] = {
|
||||||
"completed_on_arq": None,
|
"completed_on_arq": None,
|
||||||
"rating": 0,
|
"rating": 0,
|
||||||
|
"low_rating_suggestions": "",
|
||||||
"completed_how": None,
|
"completed_how": None,
|
||||||
"arq_helped": [],
|
"arq_helped": [],
|
||||||
"excel_features": [],
|
"excel_features": [],
|
||||||
@ -163,6 +164,12 @@ def create_survey():
|
|||||||
.classes("text-3xl")
|
.classes("text-3xl")
|
||||||
.bind_value(state.feature_feedback[feature], "rating")
|
.bind_value(state.feature_feedback[feature], "rating")
|
||||||
)
|
)
|
||||||
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
|
rating, "value", backward=lambda v: 0 < v < 4
|
||||||
|
):
|
||||||
|
ui.input(label="What could have been improved for a better experience?").bind_value(
|
||||||
|
state.feature_feedback[feature], "low_rating_suggestions"
|
||||||
|
).classes("w-full")
|
||||||
|
|
||||||
with ui.column().classes("w-full").bind_visibility_from(
|
with ui.column().classes("w-full").bind_visibility_from(
|
||||||
p2q1_select, "value", backward=lambda v: v == "No"
|
p2q1_select, "value", backward=lambda v: v == "No"
|
||||||
@ -273,13 +280,15 @@ def create_survey():
|
|||||||
ui.label("Review Your Answers").classes("text-h4 mb-4")
|
ui.label("Review Your Answers").classes("text-h4 mb-4")
|
||||||
with ui.card().classes("w-full max-w-2xl p-6"):
|
with ui.card().classes("w-full max-w-2xl p-6"):
|
||||||
with ui.column().classes("w-full gap-2"):
|
with ui.column().classes("w-full gap-2"):
|
||||||
ui.markdown(f"**Frequency**: {state.frequency}").classes("text-md")
|
ui.markdown(f"**Frequency**: {state.frequency}")
|
||||||
|
if state.no_use_reason:
|
||||||
|
ui.markdown(f"**Reasons for not using**: {state.no_use_reason}")
|
||||||
feature_text = ", ".join(const.TASK_OPTIONS[i] for i in state.selected_features if i != "Others")
|
feature_text = ", ".join(const.TASK_OPTIONS[i] for i in state.selected_features if i != "Others")
|
||||||
feature_text += f", {state.other_tasks}" if state.other_tasks else ""
|
feature_text += f", {state.other_tasks}" if state.other_tasks else ""
|
||||||
ui.markdown(f"**Features**: {feature_text}").classes("text-md")
|
ui.markdown(f"**Features**: {feature_text}")
|
||||||
|
|
||||||
ui.markdown(f"**Suggestions**: {state.suggestions}").classes("text-md")
|
ui.markdown(f"**Suggestions**: {state.suggestions}")
|
||||||
ui.markdown(f"**Priority**: {', '.join(state.priority_tasks)}").classes("text-md")
|
ui.markdown(f"**Priority**: {', '.join(state.priority_tasks)}")
|
||||||
|
|
||||||
ui.separator().classes("my-2")
|
ui.separator().classes("my-2")
|
||||||
|
|
||||||
@ -289,6 +298,8 @@ def create_survey():
|
|||||||
ui.markdown(f"##### {const.TASK_OPTIONS[fe]}")
|
ui.markdown(f"##### {const.TASK_OPTIONS[fe]}")
|
||||||
if fd["completed_on_arq"] == "Yes":
|
if fd["completed_on_arq"] == "Yes":
|
||||||
ui.markdown(f"**Rating**: {fd['rating']}")
|
ui.markdown(f"**Rating**: {fd['rating']}")
|
||||||
|
if fd["low_rating_suggestions"]:
|
||||||
|
ui.markdown(f"**Suggestions**: {fd['low_rating_suggestions']}")
|
||||||
if fd["arq_helped"]:
|
if fd["arq_helped"]:
|
||||||
ui.markdown(f"**Arq helped**: {', '.join(fd['arq_helped'])}")
|
ui.markdown(f"**Arq helped**: {', '.join(fd['arq_helped'])}")
|
||||||
if fd["excel_features"]:
|
if fd["excel_features"]:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user