diff --git a/frontend/app.py b/frontend/app.py index 8104401..64f87ef 100644 --- a/frontend/app.py +++ b/frontend/app.py @@ -1,29 +1,39 @@ +# Import necessary modules import dash import dash_bootstrap_components as dbc from flask_caching import Cache from utils.external_assets import FONT_AWSOME, CUSTOM_STYLE from layout.layout import layout +# Set up the Dash app with Flask server app = dash.Dash( - __name__, - # server=application, - suppress_callback_exceptions=True, - external_stylesheets=[ - dbc.themes.BOOTSTRAP, - FONT_AWSOME, - CUSTOM_STYLE + __name__, # Name of the application + suppress_callback_exceptions=True, # Suppress callback exceptions if True + external_stylesheets=[ # List of external stylesheets + dbc.themes.BOOTSTRAP, # Use the Bootstrap theme + FONT_AWSOME, # Use Font Awesome + CUSTOM_STYLE, # Use a custom stylesheet + 'assets/custom.css' # use for Chatbot ], - meta_tags=[ + meta_tags=[ # List of meta tags to include in the HTML head {"name": "viewport", "content": "width=device-width, initial-scale=1, maximum-scale=1.2, minimum-scale=0.9"} ] ) -application = app.server # define flask application.server +# Define the Flask server instance and assign it to a variable named 'application' +application = app.server + +# Set up a cache instance using Flask-Caching to cache the app's computed data cache = Cache(app.server, config={ 'CACHE_TYPE': 'FileSystemCache', 'CACHE_DIR': 'cache-directory' }) +# Set the app's title to 'DolFin' app.title = 'DolFin' + +# Log a message to the app's logger for testing purposes app.logger.info('testing log') -app.layout = layout \ No newline at end of file + +# Set the app's layout to the 'layout' variable defined in another file +app.layout = layout diff --git a/frontend/application.py b/frontend/application.py index d1d99b4..e89ce15 100644 --- a/frontend/application.py +++ b/frontend/application.py @@ -1,27 +1,33 @@ +# Import necessary modules from app import app, application from classes.auth import Auth import dash_core_components as dcc from dash.dependencies import Input, Output, State from utils.constants import home_page_location, login_location, dashboard_location, breakdown_location, news_location +# Import the various pages of the web app from pages.home import home from pages.login import login from pages.dashboard import dashboard from pages.breakdown import breakdown from pages.news import news +# Import callback functions for the sidebar from layout.sidebar.sidebar_callbacks import toggle_collapse, toggle_classname +# Define a callback function that determines the appropriate page layout based on the current URL pathname @app.callback( - Output("page-content", "children"), - Input("url", "pathname"), - State("url", "pathname") + Output("page-content", "children"), # Output is the "page-content" div and its children + Input("url", "pathname"), # Input is the current URL pathname + State("url", "pathname") # State is the current URL pathname ) - def render_page_content(pathname, state_path): + # If the current URL pathname is the login page, return the login layout if pathname == login_location: return login.layout + # If the user is authenticated... if Auth.is_authenticated(): + # Check the current URL pathname and return the appropriate layout for each page if pathname == home_page_location: return home.layout if pathname == dashboard_location: @@ -31,7 +37,9 @@ def render_page_content(pathname, state_path): if pathname == news_location: return news.layout else: + # If the user is not authenticated, return a message prompting them to authenticate and redirecting them to the login page return dcc.Link("Oh Dear, Appears you need to Authenticate, Click this to head back to login..", href=login_location) +# Run the Flask application if __name__ == "__main__": - application.run(port=8080, debug=True, load_dotenv=True) + application.run(port=8080, debug=True, load_dotenv=True) \ No newline at end of file diff --git a/frontend/assets/custom.css b/frontend/assets/custom.css new file mode 100644 index 0000000..343e4f5 --- /dev/null +++ b/frontend/assets/custom.css @@ -0,0 +1,48 @@ +/* Chatbox Styles */ +.chat-wrapper { + position: fixed; + bottom: 5px; + right: 20px; +} + +.chat-button { + background-color: #007BFF; + color: white; + padding: 2px 10px; /* Increase padding horizontally for a wider button */ + cursor: pointer; + border: none; + outline: none; + width: 200px; /* Set a specific width for the button */ + height: 40px; +} + +.chat-container { + display: none; + background-color: #F8F9FA; + padding: 10px; + border: 1px solid #CED4DA; +} + +.chat-messages { + max-height: 200px; + overflow-y: scroll; +} + +.chat-input { + margin-top: 10px; + width: 100%; + padding: 5px; + border: 1px solid #CED4DA; + border-radius: 3px; +} + +.logo-image { + height: 20px; + width: auto; + margin-right: 5px; +} + +.chat-title { + font-size: 14px; + font-weight: bold; +} diff --git a/frontend/layout/layout.py b/frontend/layout/layout.py index 3f5ec8b..e4f0df1 100644 --- a/frontend/layout/layout.py +++ b/frontend/layout/layout.py @@ -7,14 +7,51 @@ content = html.Div(id="page-content", className="content-container") -# Wrap the content, sidebar, and footer inside a new div with the "page-container" class +# Define the chatbox component with unique IDs +chatbox = html.Div( + [ + html.Div( + [ + html.Img( + src="assets/images/logo_small.png", + className="logo-image" + ), + html.Span("Chat with me", className="chat-title") + ], + id="chat-button-unique", + className="chat-button" + ), + html.Div( + id="chat-container-unique", + className="chat-container", + children=[ + html.Div( + id="chat-messages-unique", + className="chat-messages" + ), + dcc.Input( + id="chat-input-unique", + className="chat-input", + placeholder="Type your message..." + ), + ], + ), + ], + className="chat-wrapper" +) + + +# Wrap the content, sidebar, chatbox, and footer inside a new div with the "page-container" class page_container = html.Div( [ sidebar, content, + chatbox, # Added the chatbox component + #Footer(), # Add the Footer component ], className="page-container", ) +# Define the top-level layout with chatbox included layout = html.Div([dcc.Location(id="url"), navbar, logo, page_container]) diff --git a/frontend/layout/sidebar/sidebar_callbacks.py b/frontend/layout/sidebar/sidebar_callbacks.py index 34a9e6e..bfe52c7 100644 --- a/frontend/layout/sidebar/sidebar_callbacks.py +++ b/frontend/layout/sidebar/sidebar_callbacks.py @@ -1,8 +1,6 @@ from dash.dependencies import Input, Output, State - from app import app - @app.callback( Output("sidebar", "className"), [Input("sidebar-toggle", "n_clicks")], @@ -13,7 +11,6 @@ def toggle_classname(n, classname): return "collapsed" return "" - @app.callback( Output("collapse", "is_open"), [Input("navbar-toggle", "n_clicks")], @@ -22,4 +19,22 @@ def toggle_classname(n, classname): def toggle_collapse(n, is_open): if n: return not is_open - return is_open \ No newline at end of file + return is_open + +@app.callback( + [Output("chat-container-unique", "style"), Output("chat-messages-unique", "children")], + [Input("chat-button-unique", "n_clicks")], + [State("chat-container-unique", "style")] +) +def toggle_chatbox(n_clicks, chat_container_style): + if not chat_container_style: + chat_container_style = {"display": "none"} + + if n_clicks and n_clicks % 2 != 0: + chat_container_style["display"] = "block" + else: + chat_container_style["display"] = "none" + + # Add any additional logic for handling chat messages + + return chat_container_style, None