diff --git a/.gitignore b/.gitignore index feec240e..44abdd5d 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ yarn-debug.log* yarn-error.log* .vs/ -*.sqlite \ No newline at end of file +*.sqlite + +src/fragmentTypes.json \ No newline at end of file diff --git a/src/assets/Artboard 4_100.png b/src/assets/Artboard 4_100.png new file mode 100644 index 00000000..2ebf8433 Binary files /dev/null and b/src/assets/Artboard 4_100.png differ diff --git a/src/assets/Tickets-small.png b/src/assets/Tickets-small.png new file mode 100644 index 00000000..8cdb141d Binary files /dev/null and b/src/assets/Tickets-small.png differ diff --git a/src/assets/Tickets.png b/src/assets/Tickets.png new file mode 100644 index 00000000..371d71c4 Binary files /dev/null and b/src/assets/Tickets.png differ diff --git a/src/assets/inactivity_100.png b/src/assets/inactivity_100.png new file mode 100644 index 00000000..6a40671b Binary files /dev/null and b/src/assets/inactivity_100.png differ diff --git a/src/assets/team-change_100.png b/src/assets/team-change_100.png new file mode 100644 index 00000000..98d30071 Binary files /dev/null and b/src/assets/team-change_100.png differ diff --git a/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/index.js b/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/index.js index 707cf253..d4e73703 100644 --- a/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/index.js +++ b/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/index.js @@ -8,7 +8,6 @@ import team_progress_sentiment_buttons from "./team_progress_sentiment_buttons.j import voyage_application_tier_select from "./voyage_application_tier_select"; import three_buttons from './three_buttons'; import skill_setter from './SkillSetter'; -import multiple_text_input from './multiple_text_input'; export default { checkbox, @@ -22,5 +21,5 @@ export default { team_progress_sentiment_buttons, three_buttons, skill_setter, - multiple_text_input + }; diff --git a/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/multiple_text_input.jsx b/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/multiple_text_input.jsx deleted file mode 100644 index 0aca9329..00000000 --- a/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/multiple_text_input.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import text from "./text"; - -const multiple_text_input = (data, onFormChange, form_data) => { - return ( -
- {data.options.map((answer, index) => { - return; - })} -
- ) -} - -export default multiple_text_input; diff --git a/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/voyage_application_tier_select.jsx b/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/voyage_application_tier_select.jsx index 0f46344a..b0347bc6 100644 --- a/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/voyage_application_tier_select.jsx +++ b/src/components/DynamicForm/components/DynamicFormMaker/QuestionComponents/voyage_application_tier_select.jsx @@ -20,6 +20,21 @@ class TierSelectRadioComponent extends React.Component { } ] const { answer, field_name, index, onFormChange, form_data } = this.props; + let subtext; + switch (answer.value) { + case 1: + subtext =

HTML / Basic Javascript / Basic Algorithms (Landing Pages)

; + break; + case 2: + subtext =

Intermediate Algorithms / Front-end Projects (Front-End)

; + break; + case 3: + subtext =

Advanced Projects / Data Visualization / Back-end (Full-Stack)

; + break; + default: + subtext =

HTML / Basic Javascript / Basic Algorithms (Landing Pages)

; + break; + } return (
@@ -28,13 +43,8 @@ class TierSelectRadioComponent extends React.Component { {'badge-'
{`Tier ${answer.text}`}
- {/* im sorry... */}
- { - answer.value === 1 &&

HTML / Basic Javascript / Basic Algorithms (Landing Pages)

|| - answer.value === 2 &&

Intermediate Algorithms / Front-end Projects (Front-End)

|| - answer.value === 3 &&

Advanced Projects / Data Visualization / Back-end (Full-Stack)

- } + {subtext}
{ @@ -14,16 +13,15 @@ const NewsFeed = ({ type, loading, data }) => { ${project ? `${project.team_name.toUpperCase()}` : "ALL"} NEWS `; - - const renderNewsfeedItems = items => items.map( - item => { - return FeedItemContainer({ - component: NewsfeedItems[item.type], - item, - key: item.id, - }) - } - ); + // const renderNewsfeedItems = items => items.map( + // item => { + // return FeedItemContainer({ + // component: NewsfeedItems[item.type], + // item, + // key: item.id, + // }) + // } + // ); const renderStandups = standups => standups.map( standup => ( diff --git a/src/components/ProjectCard/CohortProjectInfo.jsx b/src/components/ProjectCard/CohortProjectInfo.jsx index 33886139..abf95b1c 100644 --- a/src/components/ProjectCard/CohortProjectInfo.jsx +++ b/src/components/ProjectCard/CohortProjectInfo.jsx @@ -1,4 +1,4 @@ -import React, { Fragment } from "react"; +import React from "react"; import dateFormatter from "../utilities/dateFormatter.js" const CohortProjectInfo = ({ project }) => { diff --git a/src/components/ProjectCard/ProjectImage.jsx b/src/components/ProjectCard/ProjectImage.jsx index 016507d8..daa8f8f8 100644 --- a/src/components/ProjectCard/ProjectImage.jsx +++ b/src/components/ProjectCard/ProjectImage.jsx @@ -5,6 +5,7 @@ const ProjectImage = ({ project }) => { return ( project-img
Work In Progress
diff --git a/src/components/ProjectCard/ProjectInfo.jsx b/src/components/ProjectCard/ProjectInfo.jsx index 8987198d..c10e8101 100644 --- a/src/components/ProjectCard/ProjectInfo.jsx +++ b/src/components/ProjectCard/ProjectInfo.jsx @@ -1,4 +1,4 @@ -import React, { Fragment } from "react"; +import React from "react"; import { Link } from "react-router-dom" const ProjectInfo = ({ project }) => { diff --git a/src/components/ProjectCard/index.jsx b/src/components/ProjectCard/index.jsx index bf617857..34d4d568 100644 --- a/src/components/ProjectCard/index.jsx +++ b/src/components/ProjectCard/index.jsx @@ -3,7 +3,6 @@ import CohortProjectInfo from './CohortProjectInfo'; import ProjectImage from './ProjectImage'; import ProjectInfo from './ProjectInfo'; import TeamButtons from './TeamButtons'; -import TeamResourceLinks from './TeamResourceLinks'; import './ProjectCard.css'; import './TeamCard.css'; diff --git a/src/components/Ticketbox/Ticketbox.scss b/src/components/Ticketbox/Ticketbox.scss index db96b5e1..5a9924d6 100644 --- a/src/components/Ticketbox/Ticketbox.scss +++ b/src/components/Ticketbox/Ticketbox.scss @@ -10,7 +10,7 @@ .ticketbox-btn--main { background-color: $theme-green; color: white; - font-size: 60px; + font-size: 55px; width: 90px; height: 90px; border-radius: 50%; @@ -25,18 +25,22 @@ PLACEMENT OF MODALS ========================== */ -.bug-suggestion-box, -.ticketbox-btn-section { +.bug-suggestion-box { position: absolute; right: 20px; bottom: 120px; background-color: white; box-shadow: $box-shadow; padding: 30px; - width: 380px; + width: 400px; max-height: calc(100vh - 200px); overflow-y: auto; } +.ticketbox-btn-section { + position: absolute; + right: 15px; + bottom: 120px; +} /* ========================== TICKETBOX MAIN BTN SELECTION @@ -68,6 +72,8 @@ TICKETBOX MAIN BTN SELECTION display: grid; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); grid-gap: 15px; + align-items: center; + justify-items: end; } .ticketbox-btn--container { @@ -75,7 +81,8 @@ TICKETBOX MAIN BTN SELECTION cursor: pointer; transition: all .075s ease-out; display: grid; - justify-items: center; + justify-items: end; + align-items: center; &:hover { transform: scale(1.1); } @@ -84,9 +91,26 @@ TICKETBOX MAIN BTN SELECTION transform: none; } } + + .ticketbox-btn--text { + display: none; + color: white; + background-color: $darker-grey; + font-weight: 600; + letter-spacing: 1.2px; + text-transform: capitalize; + justify-self: end; + border-radius: 5px; + width: auto; + position: relative; + padding: 8px; + right: 70px; + margin-top: -65px; + white-space: nowrap + } .ticketbox-btn { - width: 80px; - height: 80px; + width: 60px; + height: 60px; border-radius: 50%; background-color: none; box-shadow: $box-shadow; @@ -94,14 +118,12 @@ TICKETBOX MAIN BTN SELECTION &.disabled { cursor: default; } + &:hover + .ticketbox-btn--text { + display: block; + } + } -.ticketbox-btn--text { - color: $dark-grey; - text-transform: uppercase; - letter-spacing: 1.5px; - width: 100px; - margin-top: 10px; -} + /* ========================== BUG & SUGGESTION FORMS @@ -124,6 +146,10 @@ BUG & SUGGESTION FORMS .color--help { background-color: $help; } + +.color--tickets { + background-color: #1B1464; +} .box-icon { display: block; margin: 0 auto; @@ -188,9 +214,9 @@ FORM STYLING margin-bottom: 20px; } .form-question { - text-transform: uppercase; + // text-transform: uppercase; letter-spacing: 1.3px; - color: $grey; + color: $darker-grey; padding-bottom: 5px; font-size: 12px; } @@ -266,4 +292,8 @@ SUCCESS FORM font-weight: 400; line-height: 20px; } +} + +.tickets-container { + background-color: $palest-grey !important; } \ No newline at end of file diff --git a/src/components/Ticketbox/components/Feedback/BugSuggestion.jsx b/src/components/Ticketbox/components/Feedback/BugSuggestion.jsx index 1c28f70f..b1817390 100644 --- a/src/components/Ticketbox/components/Feedback/BugSuggestion.jsx +++ b/src/components/Ticketbox/components/Feedback/BugSuggestion.jsx @@ -87,6 +87,6 @@ export default props => ( {...props} query={siteLocationEnumQuery} component={BugSuggestion} - loader + loader={{size: 'small', color: 'rgba:(0,0,0,0)'}} /> ); diff --git a/src/components/Ticketbox/components/HelpRequest/index.jsx b/src/components/Ticketbox/components/HelpRequest/index.jsx index 911e33ab..577264b9 100644 --- a/src/components/Ticketbox/components/HelpRequest/index.jsx +++ b/src/components/Ticketbox/components/HelpRequest/index.jsx @@ -1,10 +1,13 @@ import React from 'react'; +import PropTypes from 'prop-types'; import Select from 'react-select'; import { gql } from 'apollo-boost'; - import questions from './questions'; -import { client } from '../../../../index' +import { client } from '../../../../index'; +import BackBtn from '../BackBtn'; +import TicketBoxError from '../TicketBoxError'; import { DynamicFormContainer } from '../../../DynamicForm'; +import Request from "../../../utilities/Request" const createHelpRequestMutation = gql` mutation createHelpRequestMutation($help_request_data: HelpRequestData!) { @@ -14,8 +17,6 @@ const createHelpRequestMutation = gql` } `; -// todo: refactor to export with Request -// use data to limit HR options const projectHelpRequestQuery = gql` query projectHelpRequestQuery { user { @@ -45,7 +46,10 @@ const projectHelpRequestQuery = gql` class HelpRequest extends React.Component { constructor(props) { super(props); - this.state = { request_type: 'general' }; + this.state = { + request_type: 'general', + error: null, + }; } fetchProjectRequestData = async () => { @@ -80,6 +84,10 @@ class HelpRequest extends React.Component { return { ...projectData, request_type, project_id }; }; + handleSuccess = () => this.props.switchRenderedType('requests'); + + handleError = (error) => this.setState({ error }); + handleSubmit = (formData) => { const { request_type } = this.state; const help_request_data = { context: formData.context }; @@ -89,18 +97,17 @@ class HelpRequest extends React.Component { } client.mutate({ mutation: createHelpRequestMutation, variables: { help_request_data } }) - .then(console.log) - .catch(console.log); - // todo: implement handlers - // .then(this.handleSuccess) - // .catch(this.handleError); + .then(this.handleSuccess) + .catch(this.handleError); } renderBaseForm = () => { - // todo: limit options based on user in active cohort - // REQUEST OPTIONS: change here - const REQUEST_TYPES = ['general', 'inactivity', 'change_project']; const { request_type } = this.state; + const { data: { user }} = this.props; + let request_options = ['general'] + if (user && user.active_cohort_project) { + request_options = [...request_options, 'inactivity', 'change_project']; + } return (
@@ -112,7 +119,7 @@ class HelpRequest extends React.Component { isSearchable={true} defaultValue="general" name="request_type" - options={REQUEST_TYPES.map(type => ({ label: type, value: type }))} + options={request_options.map(type => ({ label: type, value: type }))} // value={request_type} value={{ label: request_type, value: request_type }} onChange={ @@ -128,24 +135,39 @@ class HelpRequest extends React.Component { } render() { - const { request_type } = this.state; + const { request_type, error } = this.state; + const { switchRenderedType } = this.props; const requestQuestions = questions[request_type](this.state); const imgFile = 'Artboard 4-small.png'; const imgSrc = require(`../../../../assets/${imgFile}`); + if (error) return ; return (
icon
- {this.renderBaseForm()} - +
+ {this.renderBaseForm()} + + +
); } } -export default HelpRequest; +HelpRequest.propTypes = { + switchRenderedType: PropTypes.func, +}; + +export default props => ( + +); diff --git a/src/components/Ticketbox/components/RequestList/HelpRequestCard.jsx b/src/components/Ticketbox/components/RequestList/HelpRequestCard.jsx new file mode 100644 index 00000000..283096c3 --- /dev/null +++ b/src/components/Ticketbox/components/RequestList/HelpRequestCard.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import './HelpRequestCard.css'; +import dateFormatter from './../../../utilities/dateFormatter'; + +const getRequestIconpath = (type) => { + let imgFile; + switch (type) { + case 'ChangeProject': + imgFile = 'team-change_100.png'; + break; + case 'InactiveMember': + imgFile = 'inactivity_100.png'; + break; + default: + imgFile = `Artboard 4_100.png`; + break; + } + return require(`../../../../assets/${imgFile}`); +}; + +const getTicketType = ({ type, inactive_member, requested_project }) => { + switch (type) { + case 'ChangeProject': + return `Project Team Change: ${requested_project ? requested_project.title : 'Auto-Placement'}` + case 'InactiveMember': + return `Inactive Member: ${inactive_member.username}` + default: + return 'Help Request' + } +}; + +const HelpRequestCard = (helpRequest) => { + const { + type, + status, + context, + created_at, + resolved_at, + admin_notes, + requested_project, + inactive_member, + // last_contact + } = helpRequest; + + const STATUS_ICON_PATHS = { + open:
, + closed:
, + }; + + const statusIconPath = STATUS_ICON_PATHS[status]; + const requestIconPath = getRequestIconpath(type); + const ticketType = getTicketType({ type, inactive_member, requested_project }); + + return ( + + {statusIconPath} +
+ + ticketbox-icon +
{ticketType}
+
+ {`Opened ${dateFormatter(created_at)}`} +
+
+ {context} +
+ { + admin_notes && +
+
Admin Comments:
+ {admin_notes} +
+ } + { resolved_at &&
Resolved {dateFormatter(resolved_at)}
} +
+ +
+ + ); +}; + +export default HelpRequestCard; diff --git a/src/components/Ticketbox/components/RequestList/HelpRequestCard.scss b/src/components/Ticketbox/components/RequestList/HelpRequestCard.scss new file mode 100644 index 00000000..9c70aaca --- /dev/null +++ b/src/components/Ticketbox/components/RequestList/HelpRequestCard.scss @@ -0,0 +1,86 @@ +@import '../../../../styles/abstracts/_variables.scss'; + + +.help-request-card { + // display: grid; + // grid-template-areas: + // "status card card"; + // grid-template-columns: repeat(3, auto); + // grid-gap: 10px; +} + +.help-request-card-ticket { + grid-area: card; + display: grid; + grid-template-columns: 35px calc(100% - 35px); + grid-gap: 10px; + background-color: white; + box-shadow: $box-shadow; + padding: 10px; + margin-bottom: 10px; + font-size: 14px; + align-items: center; + color: $dark-grey; +} + +.ticketbox-tickets-title { + grid-column: 2 / -1; + font-weight: 600; +} +.ticketbox-ticket--status { + height: 50px; + width: 10px; + display: block; + position: relative; + left: -10px; + margin-bottom: -50px; +} +.ticket-open { + background-color: $health-green; +} +.ticket-closed { + +} + +.ticketbox-tickets-icon { + grid-column: 1 / 2; + width: 35px; + height: 35px; + object-fit: contain; +} + +.help-request-timestamps { + grid-column: 2 / -1; + text-align: left; + margin-top: -15px; + color: $grey; + text-transform: uppercase; + font-size: 14px; +} + +.help-request-context { + grid-column: 2 / -1; +} + +.help-request-admin_notes { + grid-column: 2 / -1; + border-top: 1px solid $light-grey; + padding-top: 10px; +} +.admin-section-header { + display: inline-block; + color: $grey; + text-transform: uppercase; + font-size: 14px; + padding-right: 10px; +} + +.ticket-status--resolved { + grid-column: 2 / -1; + display: block; + border-top: 1px solid $light-grey; + padding-top: 10px; + color: $grey; + text-transform: uppercase; + font-size: 14px; +} \ No newline at end of file diff --git a/src/components/Ticketbox/components/RequestList/index.jsx b/src/components/Ticketbox/components/RequestList/index.jsx new file mode 100644 index 00000000..3ee299bb --- /dev/null +++ b/src/components/Ticketbox/components/RequestList/index.jsx @@ -0,0 +1,93 @@ +import React from "react"; +import { gql } from "apollo-boost"; +import { Request } from "../../../utilities"; +import Loader from "../../../Loader"; +import BackBtn from "../BackBtn"; +import HelpRequestCard from "./HelpRequestCard"; + +class RequestList extends React.Component { + render() { + const { + data: { user }, + loading, + switchRenderedType + } = this.props; + const imgFile = "Tickets-small.png"; + const imgSrc = require(`../../../../assets/${imgFile}`); + + let toRender; + if (loading) toRender = ; + else { + const { help_requests } = user; + if (!help_requests.length) { + toRender = + "No tickets yet! Come back after you have submitted a Bug, Suggestion or Help Ticket."; + } else { + toRender = help_requests.map(HelpRequestCard); + } + } + // todo: if allow filter by status or request_type manage state of filter tabs + // filter client side or move query to be managed by RequestList + + return ( +
+
+ icon +
+ {toRender} + +
+ ); + } +} + +const userRequestListQuery = gql` + query userRequestListQuery( + # todo: remove args if managing filtering client side + $status: HelpRequestStatus + $request_type: ProjectHelpRequestType + ) { + user { + id + # todo: remove args if managing filtering client side + help_requests(status: $status, request_type: $request_type) { + id + status + context + created_at + resolved_at + admin_notes + ... on HelpRequest { + type: __typename + } + ... on ChangeProject { + type: __typename + requested_project { + title + } + } + ... on InactiveMember { + type: __typename + inactive_member { + username + } + last_contact + } + } + } + } +`; + +export default props => ( + +); diff --git a/src/components/Ticketbox/index.jsx b/src/components/Ticketbox/index.jsx index b1d5d946..aedde56d 100644 --- a/src/components/Ticketbox/index.jsx +++ b/src/components/Ticketbox/index.jsx @@ -3,6 +3,7 @@ import PropTypes from "prop-types"; import './Ticketbox.css'; import HelpRequest from './components/HelpRequest'; import PopupMenu from "../utilities/PopupMenu" +import RequestList from './components/RequestList' import { BugSuggestion } from './components/Feedback'; class TicketboxPopup extends React.Component { @@ -14,10 +15,11 @@ class TicketboxPopup extends React.Component { switch (type) { case 'suggestion': case 'bug': - return + return ; case 'help': - return - // return + return ; + case 'your tickets': + return ; default: return } @@ -36,12 +38,14 @@ const TicketboxButtons = ({ switchRenderedType }) => { let assets = [ 'Artboard 2.png', 'Artboard 3.png', - 'Artboard 4.png' + 'Artboard 4.png', + 'Tickets.png', ]; let labels = [ 'suggestion', 'bug', - 'help' + 'help', + 'your tickets' ]; return (
@@ -71,7 +75,7 @@ TicketboxButtons.propTypes = { export default () => localStorage.token ? ( -
?
+
) diff --git a/src/components/UserProfile/index.jsx b/src/components/UserProfile/index.jsx index 2ac5db8d..0c4974d0 100644 --- a/src/components/UserProfile/index.jsx +++ b/src/components/UserProfile/index.jsx @@ -1,4 +1,4 @@ -import React, { Fragment } from "react"; +import React from "react"; import UserSideBar from "./UserSideBar"; import Request from "../utilities/Request" import profileQuery from "./graphql/profileQuery" diff --git a/src/fragmentTypes.json b/src/fragmentTypes.json index c278b1e3..083531ff 100644 --- a/src/fragmentTypes.json +++ b/src/fragmentTypes.json @@ -1 +1 @@ -{"__schema":{"types":[{"kind":"INTERFACE","name":"ProjectBase","possibleTypes":[{"name":"CohortProject"},{"name":"Project"}]},{"kind":"INTERFACE","name":"SkillInterface","possibleTypes":[{"name":"Skill"},{"name":"AcquiredSkill"},{"name":"DesiredSkill"}]},{"kind":"INTERFACE","name":"UserBase","possibleTypes":[{"name":"User"},{"name":"CohortMember"},{"name":"InactiveUser"},{"name":"ProjectMember"}]},{"kind":"INTERFACE","name":"NewsfeedItem","possibleTypes":[{"name":"GithubActivityIssue"},{"name":"GithubActivityPullRequest"},{"name":"NewsfeedVoyage"},{"name":"NewsfeedStandup"},{"name":"NewsfeedAvailableStandup"}]},{"kind":"INTERFACE","name":"HelpRequest","possibleTypes":[{"name":"TeamHelpRequest"}]},{"kind":"INTERFACE","name":"GithubActivityItem","possibleTypes":[{"name":"GithubActivityIssue"},{"name":"GithubActivityPullRequest"}]}]}} \ No newline at end of file +{"__schema":{"types":[{"kind":"INTERFACE","name":"ProjectBase","possibleTypes":[{"name":"CohortProject"},{"name":"Project"}]},{"kind":"INTERFACE","name":"SkillInterface","possibleTypes":[{"name":"Skill"},{"name":"AcquiredSkill"},{"name":"DesiredSkill"}]},{"kind":"INTERFACE","name":"UserBase","possibleTypes":[{"name":"User"},{"name":"CohortMember"},{"name":"ProjectMember"}]},{"kind":"INTERFACE","name":"HelpRequestBase","possibleTypes":[{"name":"HelpRequest"},{"name":"InactiveMember"},{"name":"ChangeProject"}]},{"kind":"INTERFACE","name":"NewsfeedItem","possibleTypes":[{"name":"GithubActivityIssue"},{"name":"GithubActivityPullRequest"},{"name":"NewsfeedVoyage"},{"name":"NewsfeedStandup"},{"name":"NewsfeedAvailableStandup"}]},{"kind":"INTERFACE","name":"GithubActivityItem","possibleTypes":[{"name":"GithubActivityIssue"},{"name":"GithubActivityPullRequest"}]}]}} \ No newline at end of file diff --git a/src/styles/abstracts/_variables.scss b/src/styles/abstracts/_variables.scss index b412dc28..4f312553 100644 --- a/src/styles/abstracts/_variables.scss +++ b/src/styles/abstracts/_variables.scss @@ -131,7 +131,7 @@ PORTALS ========================== */ @mixin portal-title { - color: $light-grey; + color: $grey; font-size: $portal-title-size; margin: 0 auto; margin-top: 120px; @@ -139,10 +139,11 @@ PORTALS text-transform: uppercase; text-align: center; display: block; + font-weight: 600; } @mixin portal-subcategory { - color: $lighter-grey; + color: $grey; font-size: $portal-subcategory-size; text-align: left; text-transform: uppercase;